diff --git a/sdk/ai/azopenaiassistants/CHANGELOG.md b/sdk/ai/azopenaiassistants/CHANGELOG.md new file mode 100644 index 000000000000..a9fa39f5f672 --- /dev/null +++ b/sdk/ai/azopenaiassistants/CHANGELOG.md @@ -0,0 +1,5 @@ +# Release History + +## 0.1.0 (2024-03-05) + +* Initial release of the `azopenaiassistants` library diff --git a/sdk/ai/azopenaiassistants/CONTRIBUTING.md b/sdk/ai/azopenaiassistants/CONTRIBUTING.md new file mode 100644 index 000000000000..4f3a97f26649 --- /dev/null +++ b/sdk/ai/azopenaiassistants/CONTRIBUTING.md @@ -0,0 +1,115 @@ +# Contributing Guide + +> NOTE: these instructions are for fixing or adding features to the `azopenaiassistants` module. To use the module refer to the readme for this package: [readme.md](https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/ai/azopenai/README.md). + +This is a contributing guide for the `azopenaiassistants` package. For general contributing guidelines refer to [CONTRIBUTING.md](https://github.com/Azure/azure-sdk-for-go/blob/main/CONTRIBUTING.md). + +The `azopenaiassistants` package can be used with either Azure OpenAI or OpenAI's public service. New features are added using our code generation process, specified using TypeSpec [TypeSpec](https://github.com/Microsoft/typespec), which details all the models and protocol methods for using OpenAI. + +### Prerequisites + +For code fixes that do not require code generation: +- Go 1.18 (or greater) + +For code generation: +- [NodeJS (use the latest LTS)](https://nodejs.org) +- [TypeSpec compiler](https://github.com/Microsoft/typespec#getting-started). +- [autorest](https://github.com/Azure/autorest/tree/main/packages/apps/autorest) +- [PowerShell Core](https://github.com/PowerShell/PowerShell#get-powershell) +- [goimports](https://pkg.go.dev/golang.org/x/tools/cmd/goimports) + +# Building + +## Generating from TypeSpec + +The `Client` is primarily generated from TypeSpec, with some handwritten code where we've changed the interface to match Azure naming conventions (for instance, we refer to Models as Deployments). Files that do not have `custom` (ex: `client.go`, `models.go`, `models_serde.go`, etc..) are generated. + +Files that have `custom` in the name are handwritten (ex: `custom_client_files.go`), while files that do not (ex: `client.go`, `models.go`, `models_serde.go`, etc..) are generated. + +### Regeneration + +The `testdata/tsp-location.yaml` specifies the specific revision (and repo) that we use to generate the client. This also makes it possible, if needed, to generate from branch commmits in [`Azure/azure-rest-api-specs`](https://github.com/Azure/azure-rest-api-specs). + +**tsp.location.yaml**: +```yaml +directory: specification/ai/OpenAI.Assistants +commit: +repo: Azure/azure-rest-api-specs +``` +The generation process is all done as `go generate` commands in `build.go`. To regenerate the client run: + +``` +go generate ./... +``` + +Commit the generated changes as part of your pull request. + +If the changes don't look quite right you can adjust the generated code using the `autorest.md` file. + +# Testing + +There are three kinds of tests for this package: unit tests, recorded tests and live tests. + +## Unit and recorded tests + +Unit tests and recorded tests do not require access to OpenAI to run and will run with any PR as a check-in gate. + +Recorded tests require the Azure SDK test proxy is running. See the instructions for [installing the test-proxy](https://github.com/Azure/azure-sdk-tools/blob/main/tools/test-proxy/Azure.Sdk.Tools.TestProxy/README.md#installation). + +In one terminal window, start the test-proxy: + +```bash +cd +test-proxy +``` + +In another terminal window: + + +To playback (ie: use recordings): +```bash +cd + +export AZURE_RECORD_MODE=playback +go test -count 1 -v ./... +``` + +To re-record: +```bash +cd + +export AZURE_RECORD_MODE=record +go test -count 1 -v ./... + +# push the recording changes to the repo +test-proxy push -a assets.json + +# commit our assets.json file now that it points +# to the new recordings. +git add assets.json +git commit -m "updated recordings" +git push +``` + +## Live tests + +### Local development + +Copy the `sample.env` file to `.env`, and fill out all the values. Each value is documented to give you a general idea of what's needed, but ultimately you'll need to work with the Azure OpenAI SDK team to figure out which services are used for which features. + +Once filled out, the tests will automatically load environment variables from the `.env`: + +```bash +export AZURE_RECORD_MODE=live +go test -count 1 -v ./... +``` + +### Pull requests + +Post a comment to your PR with this text: + +``` +/azp run go - azopenaiassistants +``` + +The build bot will post a comment indicating its started the pipeline and the checks will start showing up in the status for the PR as well. diff --git a/sdk/ai/azopenaiassistants/LICENSE.txt b/sdk/ai/azopenaiassistants/LICENSE.txt new file mode 100644 index 000000000000..ec703274aadd --- /dev/null +++ b/sdk/ai/azopenaiassistants/LICENSE.txt @@ -0,0 +1,21 @@ + MIT License + +Copyright (c) Microsoft Corporation. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE \ No newline at end of file diff --git a/sdk/ai/azopenaiassistants/README.md b/sdk/ai/azopenaiassistants/README.md new file mode 100644 index 000000000000..d69aebe98f2a --- /dev/null +++ b/sdk/ai/azopenaiassistants/README.md @@ -0,0 +1,114 @@ +# Azure OpenAI assistants client module for Go + +NOTE: this client can be used with Azure OpenAI and OpenAI. + +OpenAI assistants makes it simpler to have a create, manage and use Assistant, where conversation state is stored and managed by the service. These assistants are backed by the same powerful models you're used to with OpenAI, and also allows the use of the Code Interpreter, Retrieval and Function Calling tools. + +Use this module to: + +- Create and manage assistants, threads, messages, and runs. +- Configure and use tools with assistants. +- Upload and manage files for use with assistants. + +[Source code][azopenaiassistants_repo] | [Package (pkg.go.dev)][azopenaiassistants_pkg_go] | [REST API documentation][openai_rest_docs] | [Product documentation][openai_docs] + +## Getting started + +### Prerequisites + +* Go, version 1.18 or higher - [Install Go](https://go.dev/doc/install) +* [Azure subscription][azure_sub] +* [Azure OpenAI access][azure_openai_access] + +### Install the packages + +Install the `azopenaiassistants` and `azidentity` modules with `go get`: + +```bash +go get github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants + +# optional +go get github.com/Azure/azure-sdk-for-go/sdk/azidentity +``` + +The [azidentity][azure_identity] module is used for Azure Active Directory authentication with Azure OpenAI. + +### Authentication + +#### Azure OpenAI + +Azure OpenAI clients can authenticate using Azure Active Directory or with an API key: + +* Using Azure Active Directory, with a TokenCredential: [example][azopenaiassistants_example_tokencredential] +* Using an API key: [example][azopenaiassistants_example_keycredential] + +#### OpenAI + +OpenAI supports connecting using an API key: [example][azopenaiassistants_example_openai]. + +## Key concepts + +See [Key concepts][openai_key_concepts_assistants] in the product documentation for more details about general concepts. + +# Examples + +Examples for various scenarios can be found on [pkg.go.dev][azopenaiassistants_examples] or in the example*_test.go files in our GitHub repo for [azopenaiassistants][azopenaiassistants_github]. + +## Troubleshooting + +### Error Handling + +All methods that send HTTP requests return `*azcore.ResponseError` when these requests fail. `ResponseError` has error details and the raw response from the service. + +### Logging + +This module uses the logging implementation in `azcore`. To turn on logging for all Azure SDK modules, set `AZURE_SDK_GO_LOGGING` to `all`. By default, the logger writes to stderr. Use the `azcore/log` package to control log output. For example, logging only HTTP request and response events, and printing them to stdout: + +```go +import azlog "github.com/Azure/azure-sdk-for-go/sdk/azcore/log" + +// Print log events to stdout +azlog.SetListener(func(cls azlog.Event, msg string) { + fmt.Println(msg) +}) + +// Includes only requests and responses in credential logs +azlog.SetEvents(azlog.EventRequest, azlog.EventResponse) +``` + +## Contributing + +This project welcomes contributions and suggestions. Most contributions require you to agree to a [Contributor License Agreement (CLA)][cla] declaring that you have the right to, and actually do, grant us the rights to use your contribution. + +When you submit a pull request, a CLA-bot will automatically determine whether you need to provide a CLA and decorate +the PR appropriately (e.g., label, comment). Simply follow the instructions provided by the bot. You will only need to +do this once across all repos using our CLA. + +This project has adopted the [Microsoft Open Source Code of Conduct][coc]. For more information, see +the [Code of Conduct FAQ][coc_faq] or contact [opencode@microsoft.com][coc_contact] with any additional questions or +comments. + + +[azure_openai_access]: https://learn.microsoft.com/azure/cognitive-services/openai/overview#how-do-i-get-access-to-azure-openai +[azopenaiassistants_repo]: https://github.com/Azure/azure-sdk-for-go/tree/main/sdk/ai/azopenaiassistants + + +[azopenaiassistants_pkg_go]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai +[azopenaiassistants_examples]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai#pkg-examples +[azopenaiassistants_example_tokencredential]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai#example-NewClient +[azopenaiassistants_example_keycredential]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai#example-NewClientWithKeyCredential +[azopenaiassistants_example_openai]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/ai/azopenai#example-NewClientForOpenAI +[azopenaiassistants_github]: https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/ai/azopenai + + +[azure_identity]: https://pkg.go.dev/github.com/Azure/azure-sdk-for-go/sdk/azidentity +[azure_sub]: https://azure.microsoft.com/free/ +[openai_docs]: https://learn.microsoft.com/azure/cognitive-services/openai +[openai_key_concepts]: https://learn.microsoft.com/azure/cognitive-services/openai/overview#key-concepts +[openai_key_concepts_assistants]: https://platform.openai.com/docs/assistants/overview +[openai_rest_docs]: https://learn.microsoft.com/azure/cognitive-services/openai/reference +[cla]: https://cla.microsoft.com +[coc]: https://opensource.microsoft.com/codeofconduct/ +[coc_faq]: https://opensource.microsoft.com/codeofconduct/faq/ +[coc_contact]: mailto:opencode@microsoft.com +[azure_openai_quickstart]: https://learn.microsoft.com/azure/cognitive-services/openai/quickstart diff --git a/sdk/ai/azopenaiassistants/assets.json b/sdk/ai/azopenaiassistants/assets.json new file mode 100644 index 000000000000..58ea0e374649 --- /dev/null +++ b/sdk/ai/azopenaiassistants/assets.json @@ -0,0 +1,6 @@ +{ + "AssetsRepo": "Azure/azure-sdk-assets", + "AssetsRepoPrefixPath": "go", + "TagPrefix": "go/ai/azopenaiassistants", + "Tag": "go/ai/azopenaiassistants_eee72902cb" +} diff --git a/sdk/ai/azopenaiassistants/autorest.md b/sdk/ai/azopenaiassistants/autorest.md new file mode 100644 index 000000000000..f9767c640d73 --- /dev/null +++ b/sdk/ai/azopenaiassistants/autorest.md @@ -0,0 +1,33 @@ +# Go + +These settings apply only when `--go` is specified on the command line. + +``` yaml +input-file: +# PR: https://github.com/Azure/azure-rest-api-specs/pull/27076/files +#- https://raw.githubusercontent.com/Azure/azure-rest-api-specs/18c24352ad4a2e0959c0b4ec1404c3a250912f8b/specification/ai/data-plane/OpenAI.Assistants/OpenApiV2/preview/2024-02-15-preview/assistants_generated.json +- ./testdata/generated/openapi.json +output-folder: ../azopenaiassistants +clear-output-folder: false +module: github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants +license-header: MICROSOFT_MIT_NO_VERSION +openapi-type: data-plane +go: true +title: "OpenAIAssistants" +use: "@autorest/go@4.0.0-preview.63" +slice-elements-byval: true +# can't use this since it removes an innererror type that we want () +# remove-non-reference-schema: true +``` + +## Transformations + +Fix deployment and endpoint parameters so they show up in the right spots + +``` yaml +directive: + # Add x-ms-parameter-location to parameters in x-ms-parameterized-host + - from: swagger-document + where: $["x-ms-parameterized-host"].parameters.0 + transform: $["x-ms-parameter-location"] = "client"; +``` diff --git a/sdk/ai/azopenaiassistants/build.go b/sdk/ai/azopenaiassistants/build.go new file mode 100644 index 000000000000..51850a40634b --- /dev/null +++ b/sdk/ai/azopenaiassistants/build.go @@ -0,0 +1,13 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants + +//go:generate pwsh ./testdata/genopenapi.ps1 +//go:generate go run ./internal/transform + +//go:generate goimports -w ./.. +//go:generate go mod tidy diff --git a/sdk/ai/azopenaiassistants/ci.yml b/sdk/ai/azopenaiassistants/ci.yml new file mode 100644 index 000000000000..193fa06fd903 --- /dev/null +++ b/sdk/ai/azopenaiassistants/ci.yml @@ -0,0 +1,46 @@ +# NOTE: Please refer to https://aka.ms/azsdk/engsys/ci-yaml before editing this file. +trigger: + branches: + include: + - main + - feature/* + - hotfix/* + - release/* + paths: + include: + - sdk/ai/azopenaiassistants + - eng/ + +pr: + branches: + include: + - main + - feature/* + - hotfix/* + - release/* + paths: + include: + - sdk/ai/azopenaiassistants + +stages: + - template: /eng/pipelines/templates/jobs/archetype-sdk-client.yml + parameters: + # We need to allow for longer retry times with tests that run against the public endpoint + # which throttles under load. Note, I left a little wiggle room since the TimeoutInMinutes + # controls the overall pipeline and TestRunTime configures the individual `go test -timeout` parameter. + TimeoutInMinutes: 35 + TestRunTime: 30m + ServiceDirectory: "ai/azopenaiassistants" + RunLiveTests: true + UsePipelineProxy: false + CloudConfig: + Public: + SubscriptionConfigurations: + - $(sub-config-azure-cloud-test-resources) + - $(sub-config-openai-test-resources) # TestSecrets-openai + EnvVars: + AZURE_TEST_RUN_LIVE: "true" # use when utilizing the New-TestResources Script + AZURE_CLIENT_ID: $(AZOPENAIASSISTANTS_CLIENT_ID) + AZURE_CLIENT_SECRET: $(AZOPENAIASSISTANTS_CLIENT_SECRET) + AZURE_TENANT_ID: $(AZOPENAIASSISTANTS_TENANT_ID) + AZURE_SUBSCRIPTION_ID: $(AZOPENAIASSISTANTS_SUBSCRIPTION_ID) diff --git a/sdk/ai/azopenaiassistants/client.go b/sdk/ai/azopenaiassistants/client.go new file mode 100644 index 000000000000..c08f79eedde0 --- /dev/null +++ b/sdk/ai/azopenaiassistants/client.go @@ -0,0 +1,1723 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +import ( + "context" + "errors" + "io" + "net/http" + "net/url" + "strconv" + "strings" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +) + +// Client contains the methods for the OpenAIAssistants group. +// Don't use this type directly, use a constructor function instead. +type Client struct { + cd clientData + internal *azcore.Client + endpoint string +} + +// CancelRun - Cancels a run of an in progress thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread being run. +// - runID - The ID of the run to cancel. +// - options - CancelRunOptions contains the optional parameters for the Client.CancelRun method. +func (client *Client) CancelRun(ctx context.Context, threadID string, runID string, options *CancelRunOptions) (CancelRunResponse, error) { + var err error + req, err := client.cancelRunCreateRequest(ctx, threadID, runID, options) + if err != nil { + return CancelRunResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return CancelRunResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return CancelRunResponse{}, err + } + resp, err := client.cancelRunHandleResponse(httpResp) + return resp, err +} + +// cancelRunCreateRequest creates the CancelRun request. +func (client *Client) cancelRunCreateRequest(ctx context.Context, threadID string, runID string, options *CancelRunOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/runs/{runId}/cancel") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if runID == "" { + return nil, errors.New("parameter runID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{runId}", url.PathEscape(runID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// cancelRunHandleResponse handles the CancelRun response. +func (client *Client) cancelRunHandleResponse(resp *http.Response) (CancelRunResponse, error) { + result := CancelRunResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadRun); err != nil { + return CancelRunResponse{}, err + } + return result, nil +} + +// CreateAssistant - Creates a new assistant. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - options - CreateAssistantOptions contains the optional parameters for the Client.CreateAssistant method. +func (client *Client) CreateAssistant(ctx context.Context, body AssistantCreationBody, options *CreateAssistantOptions) (CreateAssistantResponse, error) { + var err error + req, err := client.createAssistantCreateRequest(ctx, body, options) + if err != nil { + return CreateAssistantResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return CreateAssistantResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return CreateAssistantResponse{}, err + } + resp, err := client.createAssistantHandleResponse(httpResp) + return resp, err +} + +// createAssistantCreateRequest creates the CreateAssistant request. +func (client *Client) createAssistantCreateRequest(ctx context.Context, body AssistantCreationBody, options *CreateAssistantOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants") + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// createAssistantHandleResponse handles the CreateAssistant response. +func (client *Client) createAssistantHandleResponse(resp *http.Response) (CreateAssistantResponse, error) { + result := CreateAssistantResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.Assistant); err != nil { + return CreateAssistantResponse{}, err + } + return result, nil +} + +// CreateAssistantFile - Attaches a previously uploaded file to an assistant for use by tools that can read files. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - assistantID - The ID of the assistant to attach the file to. +// - options - CreateAssistantFileOptions contains the optional parameters for the Client.CreateAssistantFile method. +func (client *Client) CreateAssistantFile(ctx context.Context, assistantID string, body CreateAssistantFileBody, options *CreateAssistantFileOptions) (CreateAssistantFileResponse, error) { + var err error + req, err := client.createAssistantFileCreateRequest(ctx, assistantID, body, options) + if err != nil { + return CreateAssistantFileResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return CreateAssistantFileResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return CreateAssistantFileResponse{}, err + } + resp, err := client.createAssistantFileHandleResponse(httpResp) + return resp, err +} + +// createAssistantFileCreateRequest creates the CreateAssistantFile request. +func (client *Client) createAssistantFileCreateRequest(ctx context.Context, assistantID string, body CreateAssistantFileBody, options *CreateAssistantFileOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants/{assistantId}/files") + if assistantID == "" { + return nil, errors.New("parameter assistantID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{assistantId}", url.PathEscape(assistantID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// createAssistantFileHandleResponse handles the CreateAssistantFile response. +func (client *Client) createAssistantFileHandleResponse(resp *http.Response) (CreateAssistantFileResponse, error) { + result := CreateAssistantFileResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantFile); err != nil { + return CreateAssistantFileResponse{}, err + } + return result, nil +} + +// CreateMessage - Creates a new message on a specified thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to create the new message on. +// - options - CreateMessageOptions contains the optional parameters for the Client.CreateMessage method. +func (client *Client) CreateMessage(ctx context.Context, threadID string, body CreateMessageBody, options *CreateMessageOptions) (CreateMessageResponse, error) { + var err error + req, err := client.createMessageCreateRequest(ctx, threadID, body, options) + if err != nil { + return CreateMessageResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return CreateMessageResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return CreateMessageResponse{}, err + } + resp, err := client.createMessageHandleResponse(httpResp) + return resp, err +} + +// createMessageCreateRequest creates the CreateMessage request. +func (client *Client) createMessageCreateRequest(ctx context.Context, threadID string, body CreateMessageBody, options *CreateMessageOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/messages") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// createMessageHandleResponse handles the CreateMessage response. +func (client *Client) createMessageHandleResponse(resp *http.Response) (CreateMessageResponse, error) { + result := CreateMessageResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadMessage); err != nil { + return CreateMessageResponse{}, err + } + return result, nil +} + +// CreateRun - Creates a new run for an assistant thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to run. +// - createRunOptions - The details for the run to create. +// - options - CreateRunOptions contains the optional parameters for the Client.CreateRun method. +func (client *Client) CreateRun(ctx context.Context, threadID string, body CreateRunBody, options *CreateRunOptions) (CreateRunResponse, error) { + var err error + req, err := client.createRunCreateRequest(ctx, threadID, body, options) + if err != nil { + return CreateRunResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return CreateRunResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return CreateRunResponse{}, err + } + resp, err := client.createRunHandleResponse(httpResp) + return resp, err +} + +// createRunCreateRequest creates the CreateRun request. +func (client *Client) createRunCreateRequest(ctx context.Context, threadID string, body CreateRunBody, options *CreateRunOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/runs") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// createRunHandleResponse handles the CreateRun response. +func (client *Client) createRunHandleResponse(resp *http.Response) (CreateRunResponse, error) { + result := CreateRunResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadRun); err != nil { + return CreateRunResponse{}, err + } + return result, nil +} + +// CreateThread - Creates a new thread. Threads contain messages and can be run by assistants. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - options - CreateThreadOptions contains the optional parameters for the Client.CreateThread method. +func (client *Client) CreateThread(ctx context.Context, body AssistantThreadCreationOptions, options *CreateThreadOptions) (CreateThreadResponse, error) { + var err error + req, err := client.createThreadCreateRequest(ctx, body, options) + if err != nil { + return CreateThreadResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return CreateThreadResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return CreateThreadResponse{}, err + } + resp, err := client.createThreadHandleResponse(httpResp) + return resp, err +} + +// createThreadCreateRequest creates the CreateThread request. +func (client *Client) createThreadCreateRequest(ctx context.Context, body AssistantThreadCreationOptions, options *CreateThreadOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads") + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// createThreadHandleResponse handles the CreateThread response. +func (client *Client) createThreadHandleResponse(resp *http.Response) (CreateThreadResponse, error) { + result := CreateThreadResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantThread); err != nil { + return CreateThreadResponse{}, err + } + return result, nil +} + +// CreateThreadAndRun - Creates a new assistant thread and immediately starts a run using that new thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - options - CreateThreadAndRunOptions contains the optional parameters for the Client.CreateThreadAndRun method. +func (client *Client) CreateThreadAndRun(ctx context.Context, body CreateAndRunThreadOptions, options *CreateThreadAndRunOptions) (CreateThreadAndRunResponse, error) { + var err error + req, err := client.createThreadAndRunCreateRequest(ctx, body, options) + if err != nil { + return CreateThreadAndRunResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return CreateThreadAndRunResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return CreateThreadAndRunResponse{}, err + } + resp, err := client.createThreadAndRunHandleResponse(httpResp) + return resp, err +} + +// createThreadAndRunCreateRequest creates the CreateThreadAndRun request. +func (client *Client) createThreadAndRunCreateRequest(ctx context.Context, body CreateAndRunThreadOptions, options *CreateThreadAndRunOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/runs") + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// createThreadAndRunHandleResponse handles the CreateThreadAndRun response. +func (client *Client) createThreadAndRunHandleResponse(resp *http.Response) (CreateThreadAndRunResponse, error) { + result := CreateThreadAndRunResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadRun); err != nil { + return CreateThreadAndRunResponse{}, err + } + return result, nil +} + +// DeleteAssistant - Deletes an assistant. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - assistantID - The ID of the assistant to delete. +// - options - DeleteAssistantOptions contains the optional parameters for the Client.DeleteAssistant method. +func (client *Client) DeleteAssistant(ctx context.Context, assistantID string, options *DeleteAssistantOptions) (DeleteAssistantResponse, error) { + var err error + req, err := client.deleteAssistantCreateRequest(ctx, assistantID, options) + if err != nil { + return DeleteAssistantResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return DeleteAssistantResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return DeleteAssistantResponse{}, err + } + resp, err := client.deleteAssistantHandleResponse(httpResp) + return resp, err +} + +// deleteAssistantCreateRequest creates the DeleteAssistant request. +func (client *Client) deleteAssistantCreateRequest(ctx context.Context, assistantID string, options *DeleteAssistantOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants/{assistantId}") + if assistantID == "" { + return nil, errors.New("parameter assistantID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{assistantId}", url.PathEscape(assistantID)) + req, err := runtime.NewRequest(ctx, http.MethodDelete, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// deleteAssistantHandleResponse handles the DeleteAssistant response. +func (client *Client) deleteAssistantHandleResponse(resp *http.Response) (DeleteAssistantResponse, error) { + result := DeleteAssistantResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantDeletionStatus); err != nil { + return DeleteAssistantResponse{}, err + } + return result, nil +} + +// DeleteAssistantFile - Unlinks a previously attached file from an assistant, rendering it unavailable for use by tools that +// can read files. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - assistantID - The ID of the assistant from which the specified file should be unlinked. +// - fileID - The ID of the file to unlink from the specified assistant. +// - options - DeleteAssistantFileOptions contains the optional parameters for the Client.DeleteAssistantFile method. +func (client *Client) DeleteAssistantFile(ctx context.Context, assistantID string, fileID string, options *DeleteAssistantFileOptions) (DeleteAssistantFileResponse, error) { + var err error + req, err := client.deleteAssistantFileCreateRequest(ctx, assistantID, fileID, options) + if err != nil { + return DeleteAssistantFileResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return DeleteAssistantFileResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return DeleteAssistantFileResponse{}, err + } + resp, err := client.deleteAssistantFileHandleResponse(httpResp) + return resp, err +} + +// deleteAssistantFileCreateRequest creates the DeleteAssistantFile request. +func (client *Client) deleteAssistantFileCreateRequest(ctx context.Context, assistantID string, fileID string, options *DeleteAssistantFileOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants/{assistantId}/files/{fileId}") + if assistantID == "" { + return nil, errors.New("parameter assistantID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{assistantId}", url.PathEscape(assistantID)) + if fileID == "" { + return nil, errors.New("parameter fileID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{fileId}", url.PathEscape(fileID)) + req, err := runtime.NewRequest(ctx, http.MethodDelete, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// deleteAssistantFileHandleResponse handles the DeleteAssistantFile response. +func (client *Client) deleteAssistantFileHandleResponse(resp *http.Response) (DeleteAssistantFileResponse, error) { + result := DeleteAssistantFileResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantFileDeletionStatus); err != nil { + return DeleteAssistantFileResponse{}, err + } + return result, nil +} + +// DeleteFile - Delete a previously uploaded file. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - fileID - The ID of the file to delete. +// - options - DeleteFileOptions contains the optional parameters for the Client.DeleteFile method. +func (client *Client) DeleteFile(ctx context.Context, fileID string, options *DeleteFileOptions) (DeleteFileResponse, error) { + var err error + req, err := client.deleteFileCreateRequest(ctx, fileID, options) + if err != nil { + return DeleteFileResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return DeleteFileResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return DeleteFileResponse{}, err + } + resp, err := client.deleteFileHandleResponse(httpResp) + return resp, err +} + +// deleteFileCreateRequest creates the DeleteFile request. +func (client *Client) deleteFileCreateRequest(ctx context.Context, fileID string, options *DeleteFileOptions) (*policy.Request, error) { + urlPath := client.formatURL("/files/{fileId}") + if fileID == "" { + return nil, errors.New("parameter fileID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{fileId}", url.PathEscape(fileID)) + req, err := runtime.NewRequest(ctx, http.MethodDelete, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// deleteFileHandleResponse handles the DeleteFile response. +func (client *Client) deleteFileHandleResponse(resp *http.Response) (DeleteFileResponse, error) { + result := DeleteFileResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.FileDeletionStatus); err != nil { + return DeleteFileResponse{}, err + } + return result, nil +} + +// DeleteThread - Deletes an existing thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to delete. +// - options - DeleteThreadOptions contains the optional parameters for the Client.DeleteThread method. +func (client *Client) DeleteThread(ctx context.Context, threadID string, options *DeleteThreadOptions) (DeleteThreadResponse, error) { + var err error + req, err := client.deleteThreadCreateRequest(ctx, threadID, options) + if err != nil { + return DeleteThreadResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return DeleteThreadResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return DeleteThreadResponse{}, err + } + resp, err := client.deleteThreadHandleResponse(httpResp) + return resp, err +} + +// deleteThreadCreateRequest creates the DeleteThread request. +func (client *Client) deleteThreadCreateRequest(ctx context.Context, threadID string, options *DeleteThreadOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + req, err := runtime.NewRequest(ctx, http.MethodDelete, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// deleteThreadHandleResponse handles the DeleteThread response. +func (client *Client) deleteThreadHandleResponse(resp *http.Response) (DeleteThreadResponse, error) { + result := DeleteThreadResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadDeletionStatus); err != nil { + return DeleteThreadResponse{}, err + } + return result, nil +} + +// GetAssistant - Retrieves an existing assistant. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - assistantID - The ID of the assistant to retrieve. +// - options - GetAssistantOptions contains the optional parameters for the Client.GetAssistant method. +func (client *Client) GetAssistant(ctx context.Context, assistantID string, options *GetAssistantOptions) (GetAssistantResponse, error) { + var err error + req, err := client.getAssistantCreateRequest(ctx, assistantID, options) + if err != nil { + return GetAssistantResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetAssistantResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetAssistantResponse{}, err + } + resp, err := client.getAssistantHandleResponse(httpResp) + return resp, err +} + +// getAssistantCreateRequest creates the GetAssistant request. +func (client *Client) getAssistantCreateRequest(ctx context.Context, assistantID string, options *GetAssistantOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants/{assistantId}") + if assistantID == "" { + return nil, errors.New("parameter assistantID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{assistantId}", url.PathEscape(assistantID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// getAssistantHandleResponse handles the GetAssistant response. +func (client *Client) getAssistantHandleResponse(resp *http.Response) (GetAssistantResponse, error) { + result := GetAssistantResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.Assistant); err != nil { + return GetAssistantResponse{}, err + } + return result, nil +} + +// GetAssistantFile - Retrieves a file attached to an assistant. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - assistantID - The ID of the assistant associated with the attached file. +// - fileID - The ID of the file to retrieve. +// - options - GetAssistantFileOptions contains the optional parameters for the Client.GetAssistantFile method. +func (client *Client) GetAssistantFile(ctx context.Context, assistantID string, fileID string, options *GetAssistantFileOptions) (GetAssistantFileResponse, error) { + var err error + req, err := client.getAssistantFileCreateRequest(ctx, assistantID, fileID, options) + if err != nil { + return GetAssistantFileResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetAssistantFileResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetAssistantFileResponse{}, err + } + resp, err := client.getAssistantFileHandleResponse(httpResp) + return resp, err +} + +// getAssistantFileCreateRequest creates the GetAssistantFile request. +func (client *Client) getAssistantFileCreateRequest(ctx context.Context, assistantID string, fileID string, options *GetAssistantFileOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants/{assistantId}/files/{fileId}") + if assistantID == "" { + return nil, errors.New("parameter assistantID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{assistantId}", url.PathEscape(assistantID)) + if fileID == "" { + return nil, errors.New("parameter fileID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{fileId}", url.PathEscape(fileID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// getAssistantFileHandleResponse handles the GetAssistantFile response. +func (client *Client) getAssistantFileHandleResponse(resp *http.Response) (GetAssistantFileResponse, error) { + result := GetAssistantFileResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantFile); err != nil { + return GetAssistantFileResponse{}, err + } + return result, nil +} + +// GetFile - Returns information about a specific file. Does not retrieve file content. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - fileID - The ID of the file to retrieve. +// - options - GetFileOptions contains the optional parameters for the Client.GetFile method. +func (client *Client) GetFile(ctx context.Context, fileID string, options *GetFileOptions) (GetFileResponse, error) { + var err error + req, err := client.getFileCreateRequest(ctx, fileID, options) + if err != nil { + return GetFileResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetFileResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetFileResponse{}, err + } + resp, err := client.getFileHandleResponse(httpResp) + return resp, err +} + +// getFileCreateRequest creates the GetFile request. +func (client *Client) getFileCreateRequest(ctx context.Context, fileID string, options *GetFileOptions) (*policy.Request, error) { + urlPath := client.formatURL("/files/{fileId}") + if fileID == "" { + return nil, errors.New("parameter fileID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{fileId}", url.PathEscape(fileID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// getFileHandleResponse handles the GetFile response. +func (client *Client) getFileHandleResponse(resp *http.Response) (GetFileResponse, error) { + result := GetFileResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.OpenAIFile); err != nil { + return GetFileResponse{}, err + } + return result, nil +} + +// GetMessage - Gets an existing message from an existing thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to retrieve the specified message from. +// - messageID - The ID of the message to retrieve from the specified thread. +// - options - GetMessageOptions contains the optional parameters for the Client.GetMessage method. +func (client *Client) GetMessage(ctx context.Context, threadID string, messageID string, options *GetMessageOptions) (GetMessageResponse, error) { + var err error + req, err := client.getMessageCreateRequest(ctx, threadID, messageID, options) + if err != nil { + return GetMessageResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetMessageResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetMessageResponse{}, err + } + resp, err := client.getMessageHandleResponse(httpResp) + return resp, err +} + +// getMessageCreateRequest creates the GetMessage request. +func (client *Client) getMessageCreateRequest(ctx context.Context, threadID string, messageID string, options *GetMessageOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/messages/{messageId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if messageID == "" { + return nil, errors.New("parameter messageID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{messageId}", url.PathEscape(messageID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// getMessageHandleResponse handles the GetMessage response. +func (client *Client) getMessageHandleResponse(resp *http.Response) (GetMessageResponse, error) { + result := GetMessageResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadMessage); err != nil { + return GetMessageResponse{}, err + } + return result, nil +} + +// GetMessageFile - Gets information about a file attachment to a message within a thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread containing the message to get information from. +// - messageID - The ID of the message to get information from. +// - fileID - The ID of the file to get information about. +// - options - GetMessageFileOptions contains the optional parameters for the Client.GetMessageFile method. +func (client *Client) GetMessageFile(ctx context.Context, threadID string, messageID string, fileID string, options *GetMessageFileOptions) (GetMessageFileResponse, error) { + var err error + req, err := client.getMessageFileCreateRequest(ctx, threadID, messageID, fileID, options) + if err != nil { + return GetMessageFileResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetMessageFileResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetMessageFileResponse{}, err + } + resp, err := client.getMessageFileHandleResponse(httpResp) + return resp, err +} + +// getMessageFileCreateRequest creates the GetMessageFile request. +func (client *Client) getMessageFileCreateRequest(ctx context.Context, threadID string, messageID string, fileID string, options *GetMessageFileOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/messages/{messageId}/files/{fileId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if messageID == "" { + return nil, errors.New("parameter messageID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{messageId}", url.PathEscape(messageID)) + if fileID == "" { + return nil, errors.New("parameter fileID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{fileId}", url.PathEscape(fileID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// getMessageFileHandleResponse handles the GetMessageFile response. +func (client *Client) getMessageFileHandleResponse(resp *http.Response) (GetMessageFileResponse, error) { + result := GetMessageFileResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.MessageFile); err != nil { + return GetMessageFileResponse{}, err + } + return result, nil +} + +// GetRun - Gets an existing run from an existing thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to retrieve run information from. +// - runID - The ID of the thread to retrieve information about. +// - options - GetRunOptions contains the optional parameters for the Client.GetRun method. +func (client *Client) GetRun(ctx context.Context, threadID string, runID string, options *GetRunOptions) (GetRunResponse, error) { + var err error + req, err := client.getRunCreateRequest(ctx, threadID, runID, options) + if err != nil { + return GetRunResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetRunResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetRunResponse{}, err + } + resp, err := client.getRunHandleResponse(httpResp) + return resp, err +} + +// getRunCreateRequest creates the GetRun request. +func (client *Client) getRunCreateRequest(ctx context.Context, threadID string, runID string, options *GetRunOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/runs/{runId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if runID == "" { + return nil, errors.New("parameter runID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{runId}", url.PathEscape(runID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// getRunHandleResponse handles the GetRun response. +func (client *Client) getRunHandleResponse(resp *http.Response) (GetRunResponse, error) { + result := GetRunResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadRun); err != nil { + return GetRunResponse{}, err + } + return result, nil +} + +// GetRunStep - Gets a single run step from a thread run. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread that was run. +// - runID - The ID of the specific run to retrieve the step from. +// - stepID - The ID of the step to retrieve information about. +// - options - GetRunStepOptions contains the optional parameters for the Client.GetRunStep method. +func (client *Client) GetRunStep(ctx context.Context, threadID string, runID string, stepID string, options *GetRunStepOptions) (GetRunStepResponse, error) { + var err error + req, err := client.getRunStepCreateRequest(ctx, threadID, runID, stepID, options) + if err != nil { + return GetRunStepResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetRunStepResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetRunStepResponse{}, err + } + resp, err := client.getRunStepHandleResponse(httpResp) + return resp, err +} + +// getRunStepCreateRequest creates the GetRunStep request. +func (client *Client) getRunStepCreateRequest(ctx context.Context, threadID string, runID string, stepID string, options *GetRunStepOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/runs/{runId}/steps/{stepId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if runID == "" { + return nil, errors.New("parameter runID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{runId}", url.PathEscape(runID)) + if stepID == "" { + return nil, errors.New("parameter stepID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{stepId}", url.PathEscape(stepID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// getRunStepHandleResponse handles the GetRunStep response. +func (client *Client) getRunStepHandleResponse(resp *http.Response) (GetRunStepResponse, error) { + result := GetRunStepResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.RunStep); err != nil { + return GetRunStepResponse{}, err + } + return result, nil +} + +// GetThread - Gets information about an existing thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to retrieve information about. +// - options - GetThreadOptions contains the optional parameters for the Client.GetThread method. +func (client *Client) GetThread(ctx context.Context, threadID string, options *GetThreadOptions) (GetThreadResponse, error) { + var err error + req, err := client.getThreadCreateRequest(ctx, threadID, options) + if err != nil { + return GetThreadResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetThreadResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetThreadResponse{}, err + } + resp, err := client.getThreadHandleResponse(httpResp) + return resp, err +} + +// getThreadCreateRequest creates the GetThread request. +func (client *Client) getThreadCreateRequest(ctx context.Context, threadID string, options *GetThreadOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// getThreadHandleResponse handles the GetThread response. +func (client *Client) getThreadHandleResponse(resp *http.Response) (GetThreadResponse, error) { + result := GetThreadResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantThread); err != nil { + return GetThreadResponse{}, err + } + return result, nil +} + +// ListAssistantFiles - Gets a list of files attached to a specific assistant, as used by tools that can read files. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - assistantID - The ID of the assistant to retrieve the list of attached files for. +// - options - ListAssistantFilesOptions contains the optional parameters for the Client.ListAssistantFiles method. +func (client *Client) internalListAssistantFiles(ctx context.Context, assistantID string, options *ListAssistantFilesOptions) (ListAssistantFilesResponse, error) { + var err error + req, err := client.listAssistantFilesCreateRequest(ctx, assistantID, options) + if err != nil { + return ListAssistantFilesResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return ListAssistantFilesResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return ListAssistantFilesResponse{}, err + } + resp, err := client.listAssistantFilesHandleResponse(httpResp) + return resp, err +} + +// listAssistantFilesCreateRequest creates the ListAssistantFiles request. +func (client *Client) listAssistantFilesCreateRequest(ctx context.Context, assistantID string, options *ListAssistantFilesOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants/{assistantId}/files") + if assistantID == "" { + return nil, errors.New("parameter assistantID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{assistantId}", url.PathEscape(assistantID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + if options != nil && options.After != nil { + reqQP.Set("after", *options.After) + } + if options != nil && options.Before != nil { + reqQP.Set("before", *options.Before) + } + if options != nil && options.Limit != nil { + reqQP.Set("limit", strconv.FormatInt(int64(*options.Limit), 10)) + } + if options != nil && options.Order != nil { + reqQP.Set("order", string(*options.Order)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// listAssistantFilesHandleResponse handles the ListAssistantFiles response. +func (client *Client) listAssistantFilesHandleResponse(resp *http.Response) (ListAssistantFilesResponse, error) { + result := ListAssistantFilesResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantFilesPage); err != nil { + return ListAssistantFilesResponse{}, err + } + return result, nil +} + +// ListAssistants - Gets a list of assistants that were previously created. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - options - ListAssistantsOptions contains the optional parameters for the Client.ListAssistants method. +func (client *Client) internalListAssistants(ctx context.Context, options *ListAssistantsOptions) (ListAssistantsResponse, error) { + var err error + req, err := client.listAssistantsCreateRequest(ctx, options) + if err != nil { + return ListAssistantsResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return ListAssistantsResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return ListAssistantsResponse{}, err + } + resp, err := client.listAssistantsHandleResponse(httpResp) + return resp, err +} + +// listAssistantsCreateRequest creates the ListAssistants request. +func (client *Client) listAssistantsCreateRequest(ctx context.Context, options *ListAssistantsOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants") + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + if options != nil && options.After != nil { + reqQP.Set("after", *options.After) + } + if options != nil && options.Before != nil { + reqQP.Set("before", *options.Before) + } + if options != nil && options.Limit != nil { + reqQP.Set("limit", strconv.FormatInt(int64(*options.Limit), 10)) + } + if options != nil && options.Order != nil { + reqQP.Set("order", string(*options.Order)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// listAssistantsHandleResponse handles the ListAssistants response. +func (client *Client) listAssistantsHandleResponse(resp *http.Response) (ListAssistantsResponse, error) { + result := ListAssistantsResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantsPage); err != nil { + return ListAssistantsResponse{}, err + } + return result, nil +} + +// ListFiles - Gets a list of previously uploaded files. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - options - ListFilesOptions contains the optional parameters for the Client.ListFiles method. +func (client *Client) ListFiles(ctx context.Context, options *ListFilesOptions) (ListFilesResponse, error) { + var err error + req, err := client.listFilesCreateRequest(ctx, options) + if err != nil { + return ListFilesResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return ListFilesResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return ListFilesResponse{}, err + } + resp, err := client.listFilesHandleResponse(httpResp) + return resp, err +} + +// listFilesCreateRequest creates the ListFiles request. +func (client *Client) listFilesCreateRequest(ctx context.Context, options *ListFilesOptions) (*policy.Request, error) { + urlPath := client.formatURL("/files") + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + if options != nil && options.Purpose != nil { + reqQP.Set("purpose", string(*options.Purpose)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// listFilesHandleResponse handles the ListFiles response. +func (client *Client) listFilesHandleResponse(resp *http.Response) (ListFilesResponse, error) { + result := ListFilesResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.FileListResponse); err != nil { + return ListFilesResponse{}, err + } + return result, nil +} + +// ListMessageFiles - Gets a list of previously uploaded files associated with a message from a thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread containing the message to list files from. +// - messageID - The ID of the message to list files from. +// - options - ListMessageFilesOptions contains the optional parameters for the Client.ListMessageFiles method. +func (client *Client) internalListMessageFiles(ctx context.Context, threadID string, messageID string, options *ListMessageFilesOptions) (ListMessageFilesResponse, error) { + var err error + req, err := client.listMessageFilesCreateRequest(ctx, threadID, messageID, options) + if err != nil { + return ListMessageFilesResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return ListMessageFilesResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return ListMessageFilesResponse{}, err + } + resp, err := client.listMessageFilesHandleResponse(httpResp) + return resp, err +} + +// listMessageFilesCreateRequest creates the ListMessageFiles request. +func (client *Client) listMessageFilesCreateRequest(ctx context.Context, threadID string, messageID string, options *ListMessageFilesOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/messages/{messageId}/files") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if messageID == "" { + return nil, errors.New("parameter messageID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{messageId}", url.PathEscape(messageID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + if options != nil && options.After != nil { + reqQP.Set("after", *options.After) + } + if options != nil && options.Before != nil { + reqQP.Set("before", *options.Before) + } + if options != nil && options.Limit != nil { + reqQP.Set("limit", strconv.FormatInt(int64(*options.Limit), 10)) + } + if options != nil && options.Order != nil { + reqQP.Set("order", string(*options.Order)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// listMessageFilesHandleResponse handles the ListMessageFiles response. +func (client *Client) listMessageFilesHandleResponse(resp *http.Response) (ListMessageFilesResponse, error) { + result := ListMessageFilesResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.MessageFilesPage); err != nil { + return ListMessageFilesResponse{}, err + } + return result, nil +} + +// ListMessages - Gets a list of messages that exist on a thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to list messages from. +// - options - ListMessagesOptions contains the optional parameters for the Client.ListMessages method. +func (client *Client) internalListMessages(ctx context.Context, threadID string, options *ListMessagesOptions) (ListMessagesResponse, error) { + var err error + req, err := client.listMessagesCreateRequest(ctx, threadID, options) + if err != nil { + return ListMessagesResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return ListMessagesResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return ListMessagesResponse{}, err + } + resp, err := client.listMessagesHandleResponse(httpResp) + return resp, err +} + +// listMessagesCreateRequest creates the ListMessages request. +func (client *Client) listMessagesCreateRequest(ctx context.Context, threadID string, options *ListMessagesOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/messages") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + if options != nil && options.After != nil { + reqQP.Set("after", *options.After) + } + if options != nil && options.Before != nil { + reqQP.Set("before", *options.Before) + } + if options != nil && options.Limit != nil { + reqQP.Set("limit", strconv.FormatInt(int64(*options.Limit), 10)) + } + if options != nil && options.Order != nil { + reqQP.Set("order", string(*options.Order)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// listMessagesHandleResponse handles the ListMessages response. +func (client *Client) listMessagesHandleResponse(resp *http.Response) (ListMessagesResponse, error) { + result := ListMessagesResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.MessagesPage); err != nil { + return ListMessagesResponse{}, err + } + return result, nil +} + +// ListRunSteps - Gets a list of run steps from a thread run. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread that was run. +// - runID - The ID of the run to list steps from. +// - options - ListRunStepsOptions contains the optional parameters for the Client.ListRunSteps method. +func (client *Client) internalListRunSteps(ctx context.Context, threadID string, runID string, options *ListRunStepsOptions) (ListRunStepsResponse, error) { + var err error + req, err := client.listRunStepsCreateRequest(ctx, threadID, runID, options) + if err != nil { + return ListRunStepsResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return ListRunStepsResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return ListRunStepsResponse{}, err + } + resp, err := client.listRunStepsHandleResponse(httpResp) + return resp, err +} + +// listRunStepsCreateRequest creates the ListRunSteps request. +func (client *Client) listRunStepsCreateRequest(ctx context.Context, threadID string, runID string, options *ListRunStepsOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/runs/{runId}/steps") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if runID == "" { + return nil, errors.New("parameter runID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{runId}", url.PathEscape(runID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + if options != nil && options.After != nil { + reqQP.Set("after", *options.After) + } + if options != nil && options.Before != nil { + reqQP.Set("before", *options.Before) + } + if options != nil && options.Limit != nil { + reqQP.Set("limit", strconv.FormatInt(int64(*options.Limit), 10)) + } + if options != nil && options.Order != nil { + reqQP.Set("order", string(*options.Order)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// listRunStepsHandleResponse handles the ListRunSteps response. +func (client *Client) listRunStepsHandleResponse(resp *http.Response) (ListRunStepsResponse, error) { + result := ListRunStepsResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.RunStepsPage); err != nil { + return ListRunStepsResponse{}, err + } + return result, nil +} + +// ListRuns - Gets a list of runs for a specified thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to list runs from. +// - options - ListRunsOptions contains the optional parameters for the Client.ListRuns method. +func (client *Client) internalListRuns(ctx context.Context, threadID string, options *ListRunsOptions) (ListRunsResponse, error) { + var err error + req, err := client.listRunsCreateRequest(ctx, threadID, options) + if err != nil { + return ListRunsResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return ListRunsResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return ListRunsResponse{}, err + } + resp, err := client.listRunsHandleResponse(httpResp) + return resp, err +} + +// listRunsCreateRequest creates the ListRuns request. +func (client *Client) listRunsCreateRequest(ctx context.Context, threadID string, options *ListRunsOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/runs") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + reqQP := req.Raw().URL.Query() + if options != nil && options.After != nil { + reqQP.Set("after", *options.After) + } + if options != nil && options.Before != nil { + reqQP.Set("before", *options.Before) + } + if options != nil && options.Limit != nil { + reqQP.Set("limit", strconv.FormatInt(int64(*options.Limit), 10)) + } + if options != nil && options.Order != nil { + reqQP.Set("order", string(*options.Order)) + } + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header["Accept"] = []string{"application/json"} + return req, nil +} + +// listRunsHandleResponse handles the ListRuns response. +func (client *Client) listRunsHandleResponse(resp *http.Response) (ListRunsResponse, error) { + result := ListRunsResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadRunsPage); err != nil { + return ListRunsResponse{}, err + } + return result, nil +} + +// SubmitToolOutputsToRun - Submits outputs from tools as requested by tool calls in a run. Runs that need submitted tool +// outputs will have a status of 'requiresaction' with a requiredaction.type of 'submittooloutputs'. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread that was run. +// - runID - The ID of the run that requires tool outputs. +// - options - SubmitToolOutputsToRunOptions contains the optional parameters for the Client.SubmitToolOutputsToRun method. +func (client *Client) SubmitToolOutputsToRun(ctx context.Context, threadID string, runID string, body SubmitToolOutputsToRunBody, options *SubmitToolOutputsToRunOptions) (SubmitToolOutputsToRunResponse, error) { + var err error + req, err := client.submitToolOutputsToRunCreateRequest(ctx, threadID, runID, body, options) + if err != nil { + return SubmitToolOutputsToRunResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return SubmitToolOutputsToRunResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return SubmitToolOutputsToRunResponse{}, err + } + resp, err := client.submitToolOutputsToRunHandleResponse(httpResp) + return resp, err +} + +// submitToolOutputsToRunCreateRequest creates the SubmitToolOutputsToRun request. +func (client *Client) submitToolOutputsToRunCreateRequest(ctx context.Context, threadID string, runID string, body SubmitToolOutputsToRunBody, options *SubmitToolOutputsToRunOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/runs/{runId}/submit_tool_outputs") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if runID == "" { + return nil, errors.New("parameter runID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{runId}", url.PathEscape(runID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// submitToolOutputsToRunHandleResponse handles the SubmitToolOutputsToRun response. +func (client *Client) submitToolOutputsToRunHandleResponse(resp *http.Response) (SubmitToolOutputsToRunResponse, error) { + result := SubmitToolOutputsToRunResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadRun); err != nil { + return SubmitToolOutputsToRunResponse{}, err + } + return result, nil +} + +// UpdateAssistant - Modifies an existing assistant. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - assistantID - The ID of the assistant to modify. +// - options - UpdateAssistantOptions contains the optional parameters for the Client.UpdateAssistant method. +func (client *Client) UpdateAssistant(ctx context.Context, assistantID string, body UpdateAssistantOptions, options *UpdateAssistantOptions) (UpdateAssistantResponse, error) { + var err error + req, err := client.updateAssistantCreateRequest(ctx, assistantID, body, options) + if err != nil { + return UpdateAssistantResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return UpdateAssistantResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return UpdateAssistantResponse{}, err + } + resp, err := client.updateAssistantHandleResponse(httpResp) + return resp, err +} + +// updateAssistantCreateRequest creates the UpdateAssistant request. +func (client *Client) updateAssistantCreateRequest(ctx context.Context, assistantID string, body UpdateAssistantOptions, options *UpdateAssistantOptions) (*policy.Request, error) { + urlPath := client.formatURL("/assistants/{assistantId}") + if assistantID == "" { + return nil, errors.New("parameter assistantID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{assistantId}", url.PathEscape(assistantID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// updateAssistantHandleResponse handles the UpdateAssistant response. +func (client *Client) updateAssistantHandleResponse(resp *http.Response) (UpdateAssistantResponse, error) { + result := UpdateAssistantResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.Assistant); err != nil { + return UpdateAssistantResponse{}, err + } + return result, nil +} + +// UpdateMessage - Modifies an existing message on an existing thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread containing the specified message to modify. +// - messageID - The ID of the message to modify on the specified thread. +// - options - UpdateMessageOptions contains the optional parameters for the Client.UpdateMessage method. +func (client *Client) UpdateMessage(ctx context.Context, threadID string, messageID string, body UpdateMessageBody, options *UpdateMessageOptions) (UpdateMessageResponse, error) { + var err error + req, err := client.updateMessageCreateRequest(ctx, threadID, messageID, body, options) + if err != nil { + return UpdateMessageResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return UpdateMessageResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return UpdateMessageResponse{}, err + } + resp, err := client.updateMessageHandleResponse(httpResp) + return resp, err +} + +// updateMessageCreateRequest creates the UpdateMessage request. +func (client *Client) updateMessageCreateRequest(ctx context.Context, threadID string, messageID string, body UpdateMessageBody, options *UpdateMessageOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/messages/{messageId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if messageID == "" { + return nil, errors.New("parameter messageID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{messageId}", url.PathEscape(messageID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// updateMessageHandleResponse handles the UpdateMessage response. +func (client *Client) updateMessageHandleResponse(resp *http.Response) (UpdateMessageResponse, error) { + result := UpdateMessageResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadMessage); err != nil { + return UpdateMessageResponse{}, err + } + return result, nil +} + +// UpdateRun - Modifies an existing thread run. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread associated with the specified run. +// - runID - The ID of the run to modify. +// - options - UpdateRunOptions contains the optional parameters for the Client.UpdateRun method. +func (client *Client) UpdateRun(ctx context.Context, threadID string, runID string, body UpdateRunBody, options *UpdateRunOptions) (UpdateRunResponse, error) { + var err error + req, err := client.updateRunCreateRequest(ctx, threadID, runID, body, options) + if err != nil { + return UpdateRunResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return UpdateRunResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return UpdateRunResponse{}, err + } + resp, err := client.updateRunHandleResponse(httpResp) + return resp, err +} + +// updateRunCreateRequest creates the UpdateRun request. +func (client *Client) updateRunCreateRequest(ctx context.Context, threadID string, runID string, body UpdateRunBody, options *UpdateRunOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}/runs/{runId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + if runID == "" { + return nil, errors.New("parameter runID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{runId}", url.PathEscape(runID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// updateRunHandleResponse handles the UpdateRun response. +func (client *Client) updateRunHandleResponse(resp *http.Response) (UpdateRunResponse, error) { + result := UpdateRunResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.ThreadRun); err != nil { + return UpdateRunResponse{}, err + } + return result, nil +} + +// UpdateThread - Modifies an existing thread. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - threadID - The ID of the thread to modify. +// - options - UpdateThreadOptions contains the optional parameters for the Client.UpdateThread method. +func (client *Client) UpdateThread(ctx context.Context, threadID string, body UpdateThreadBody, options *UpdateThreadOptions) (UpdateThreadResponse, error) { + var err error + req, err := client.updateThreadCreateRequest(ctx, threadID, body, options) + if err != nil { + return UpdateThreadResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return UpdateThreadResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return UpdateThreadResponse{}, err + } + resp, err := client.updateThreadHandleResponse(httpResp) + return resp, err +} + +// updateThreadCreateRequest creates the UpdateThread request. +func (client *Client) updateThreadCreateRequest(ctx context.Context, threadID string, body UpdateThreadBody, options *UpdateThreadOptions) (*policy.Request, error) { + urlPath := client.formatURL("/threads/{threadId}") + if threadID == "" { + return nil, errors.New("parameter threadID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{threadId}", url.PathEscape(threadID)) + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.MarshalAsJSON(req, body); err != nil { + return nil, err + } + return req, nil +} + +// updateThreadHandleResponse handles the UpdateThread response. +func (client *Client) updateThreadHandleResponse(resp *http.Response) (UpdateThreadResponse, error) { + result := UpdateThreadResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.AssistantThread); err != nil { + return UpdateThreadResponse{}, err + } + return result, nil +} + +// UploadFile - Uploads a file for use by other operations. +// If the operation fails it returns an *azcore.ResponseError type. +// +// Generated from API version 2024-02-15-preview +// - file - The file data (not filename) to upload. +// - purpose - The intended purpose of the file. +// - options - UploadFileOptions contains the optional parameters for the Client.UploadFile method. +func (client *Client) UploadFile(ctx context.Context, file io.ReadSeeker, purpose FilePurpose, options *UploadFileOptions) (UploadFileResponse, error) { + var err error + req, err := client.uploadFileCreateRequest(ctx, file, purpose, options) + if err != nil { + return UploadFileResponse{}, err + } + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return UploadFileResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return UploadFileResponse{}, err + } + resp, err := client.uploadFileHandleResponse(httpResp) + return resp, err +} + +// uploadFileHandleResponse handles the UploadFile response. +func (client *Client) uploadFileHandleResponse(resp *http.Response) (UploadFileResponse, error) { + result := UploadFileResponse{} + if err := runtime.UnmarshalAsJSON(resp, &result.OpenAIFile); err != nil { + return UploadFileResponse{}, err + } + return result, nil +} diff --git a/sdk/ai/azopenaiassistants/client_custom.go b/sdk/ai/azopenaiassistants/client_custom.go new file mode 100644 index 000000000000..7a8e585d55e2 --- /dev/null +++ b/sdk/ai/azopenaiassistants/client_custom.go @@ -0,0 +1,133 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants + +import ( + "net/http" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +) + +const ( + clientName = "azopenaiassistants.Client" + tokenScope = "https://cognitiveservices.azure.com/.default" +) + +// ClientOptions contains optional settings for Client. +type ClientOptions struct { + azcore.ClientOptions +} + +// NewClient creates a new instance of Client that connects to an Azure OpenAI endpoint. +// - endpoint - Azure OpenAI service endpoint, for example: https://{your-resource-name}.openai.azure.com +// - credential - used to authorize requests. Usually a credential from [github.com/Azure/azure-sdk-for-go/sdk/azidentity]. +// - options - client options, pass nil to accept the default values. +func NewClient(endpoint string, credential azcore.TokenCredential, options *ClientOptions) (*Client, error) { + if options == nil { + options = &ClientOptions{} + } + + authPolicy := runtime.NewBearerTokenPolicy(credential, []string{tokenScope}, nil) + azcoreClient, err := azcore.NewClient(clientName, version, runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy, &azureOpenAIPolicy{}}}, &options.ClientOptions) + + if err != nil { + return nil, err + } + + return &Client{ + endpoint: endpoint, + internal: azcoreClient, + cd: clientData{ + azure: true, + }, + }, nil +} + +// NewClientWithKeyCredential creates a new instance of Client that connects to an Azure OpenAI endpoint. +// - endpoint - Azure OpenAI service endpoint, for example: https://{your-resource-name}.openai.azure.com +// - credential - used to authorize requests with an API Key credential +// - options - client options, pass nil to accept the default values. +func NewClientWithKeyCredential(endpoint string, credential *azcore.KeyCredential, options *ClientOptions) (*Client, error) { + if options == nil { + options = &ClientOptions{} + } + + authPolicy := runtime.NewKeyCredentialPolicy(credential, "api-key", nil) + azcoreClient, err := azcore.NewClient(clientName, version, runtime.PipelineOptions{PerRetry: []policy.Policy{authPolicy, &azureOpenAIPolicy{}}}, &options.ClientOptions) + if err != nil { + return nil, err + } + + return &Client{ + endpoint: endpoint, + internal: azcoreClient, + cd: clientData{ + azure: true, + }, + }, nil +} + +// NewClientForOpenAI creates a new instance of Client which connects to the public OpenAI endpoint. +// - endpoint - OpenAI service endpoint, for example: https://api.openai.com/v1 +// - credential - used to authorize requests with an API Key credential +// - options - client options, pass nil to accept the default values. +func NewClientForOpenAI(endpoint string, credential *azcore.KeyCredential, options *ClientOptions) (*Client, error) { + if options == nil { + options = &ClientOptions{} + } + + kp := runtime.NewKeyCredentialPolicy(credential, "authorization", &runtime.KeyCredentialPolicyOptions{ + Prefix: "Bearer ", + }) + + azcoreClient, err := azcore.NewClient(clientName, version, runtime.PipelineOptions{ + PerRetry: []policy.Policy{kp, &openAIPolicy{}}, + }, &options.ClientOptions) + + if err != nil { + return nil, err + } + + return &Client{ + endpoint: endpoint, + internal: azcoreClient, + }, nil +} + +// openAIPolicy is an internal pipeline policy to remove the api-version query parameter +type openAIPolicy struct{} + +// Do returns a function which adapts a request to target OpenAI. +// Specifically, it removes the api-version query parameter. +func (b *openAIPolicy) Do(req *policy.Request) (*http.Response, error) { + req.Raw().Header.Add("OpenAI-Beta", "assistants=v1") + return req.Next() +} + +type azureOpenAIPolicy struct{} + +func (b *azureOpenAIPolicy) Do(req *policy.Request) (*http.Response, error) { + reqQP := req.Raw().URL.Query() + reqQP.Set("api-version", string(ServiceAPIVersionsV20240215Preview)) + req.Raw().URL.RawQuery = reqQP.Encode() + req.Raw().Header.Add("OpenAI-Beta", "assistants=v1") + return req.Next() +} + +func (client *Client) formatURL(path string) string { + if client.cd.azure { + return runtime.JoinPaths("openai", path) + } + + return path +} + +type clientData struct { + azure bool +} diff --git a/sdk/ai/azopenaiassistants/client_custom_files.go b/sdk/ai/azopenaiassistants/client_custom_files.go new file mode 100644 index 000000000000..7d94c0a7989d --- /dev/null +++ b/sdk/ai/azopenaiassistants/client_custom_files.go @@ -0,0 +1,174 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "mime/multipart" + "net/http" + "net/textproto" + "net/url" + "path/filepath" + "strings" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming" +) + +func (client *Client) uploadFileCreateRequest(ctx context.Context, file io.ReadSeeker, purpose FilePurpose, options *UploadFileOptions) (*policy.Request, error) { + urlPath := client.formatURL("/files") + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + fileName := "" + + if options != nil && options.Filename != nil { + fileName = *options.Filename + } + + fileBytes, err := io.ReadAll(file) + + if err != nil { + return nil, err + } + + if err := writeMultipart(req, fileBytes, fileName, purpose); err != nil { + return nil, err + } + + return req, nil +} + +// GetFileContentResponse contains the response from the [Client.GetFileContent] function. +type GetFileContentResponse struct { + // Content is the content of the file that's been downloaded. + // NOTE: this must be Close()'d to avoid leaking resources. + Content io.ReadCloser +} + +// GetFileContentOptions contains the options for the [Client.GetFileContent] function. +type GetFileContentOptions struct { + // For future expansion +} + +// GetFileContent - Returns content for a specific file. +// If the operation fails it returns an *azcore.ResponseError type. +// +// - fileID - The ID of the file to retrieve. +// - options - GetFileContentOptions contains the optional parameters for the Client.GetFileContent method. +func (client *Client) GetFileContent(ctx context.Context, fileID string, options *GetFileContentOptions) (GetFileContentResponse, error) { + var err error + + req, err := func() (*policy.Request, error) { + urlPath := client.formatURL("/files/{fileId}/content") + if fileID == "" { + return nil, errors.New("parameter fileID cannot be empty") + } + urlPath = strings.ReplaceAll(urlPath, "{fileId}", url.PathEscape(fileID)) + req, err := runtime.NewRequest(ctx, http.MethodGet, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/octet-stream"} + return req, nil + }() + + if err != nil { + return GetFileContentResponse{}, err + } + + runtime.SkipBodyDownload(req) + httpResp, err := client.internal.Pipeline().Do(req) + if err != nil { + return GetFileContentResponse{}, err + } + if !runtime.HasStatusCode(httpResp, http.StatusOK) { + err = runtime.NewResponseError(httpResp) + return GetFileContentResponse{}, err + } + + return GetFileContentResponse{Content: httpResp.Body}, nil +} + +func writeMultipart(req *policy.Request, fileContents []byte, filename string, purpose FilePurpose) error { + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + + fileWriter, err := createFormFile(writer, "file", filename) + + if err != nil { + return err + } + + if _, err := fileWriter.Write(fileContents); err != nil { + return err + } + + if err := writer.WriteField("purpose", string(purpose)); err != nil { + return err + } + + if err := writer.Close(); err != nil { + return err + } + + return req.SetBody(streaming.NopCloser(bytes.NewReader(body.Bytes())), writer.FormDataContentType()) +} + +func createFormFile(w *multipart.Writer, fieldname, filename string) (io.Writer, error) { + h := make(textproto.MIMEHeader) + h.Set("Content-Disposition", + fmt.Sprintf(`form-data; name="%s"; filename="%s"`, + quoteReplacer.Replace(fieldname), quoteReplacer.Replace(filename))) + + contentType := openAIMimeTypes[filepath.Ext(filename)] + + if contentType == "" { + contentType = "application/octet-stream" + } + + h.Set("Content-Type", contentType) + return w.CreatePart(h) +} + +var openAIMimeTypes = map[string]string{ + ".c": "text/x-c", + ".cpp": "text/x-c++", + ".csv": "application/csv", + ".docx": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", + ".html": "text/html", + ".java": "text/x-java", + ".json": "application/json", + ".md": "text/markdown", + ".pdf": "application/pdf", + ".php": "text/x-php", + ".pptx": "application/vnd.openxmlformats-officedocument.presentationml.presentation", + ".py": "text/x-python", + ".rb": "text/x-ruby", + ".tex": "text/x-tex", + ".txt": "text/plain", + ".css": "text/css", + ".jpeg": "image/jpeg", + ".jpg": "image/jpeg", + ".js": "text/javascript", + ".gif": "image/gif", + ".png": "image/png", + ".tar": "application/x-tar", + ".ts": "application/typescript", + ".xlsx": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", + ".xml": "application/xml", + ".zip": "application/z", +} + +var quoteReplacer = strings.NewReplacer("\\", "\\\\", `"`, "\\\"") diff --git a/sdk/ai/azopenaiassistants/client_custom_files_test.go b/sdk/ai/azopenaiassistants/client_custom_files_test.go new file mode 100644 index 000000000000..e4983a42652d --- /dev/null +++ b/sdk/ai/azopenaiassistants/client_custom_files_test.go @@ -0,0 +1,79 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants_test + +import ( + "context" + "io" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/internal/recording" + "github.com/stretchr/testify/require" + + "github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants" +) + +func TestDownloadFileContent(t *testing.T) { + if recording.GetRecordMode() == recording.LiveMode { + t.Skip("Skipping non-deterministic test for live tests. Only runs in record/playback.") + } + + args := runThreadArgs{ + Assistant: azopenaiassistants.AssistantCreationBody{ + DeploymentName: &assistantsModel, + Instructions: to.Ptr("You are a helpful assistant that always draws images."), + Tools: []azopenaiassistants.ToolDefinitionClassification{ + &azopenaiassistants.CodeInterpreterToolDefinition{}, + }, + }, + Thread: azopenaiassistants.CreateAndRunThreadOptions{ + Thread: &azopenaiassistants.AssistantThreadCreationOptions{ + Messages: []azopenaiassistants.ThreadInitializationMessage{ + { + Role: to.Ptr(azopenaiassistants.MessageRoleUser), + Content: to.Ptr("Draw an image of two squares, connected by a line, as a PNG file"), + }, + }, + }, + }, + } + + client, messages := mustRunThread(context.Background(), t, args) + fileFound := false + + for _, m := range messages { + // the assistants reply should contain a file ID for an image to download + for _, c := range m.Content { + switch v := c.(type) { + case *azopenaiassistants.MessageImageFileContent: + resp, err := client.GetFileContent(context.Background(), *v.ImageFile.FileID, nil) + require.NoError(t, err) + + defer func() { + err := resp.Content.Close() + require.NoError(t, err) + }() + + fileBytes, err := io.ReadAll(resp.Content) + require.NoError(t, err) + require.NotEmpty(t, fileBytes) + fileFound = true + + t.Logf("[%s] image file ID: %s, file is %d bytes", *m.Role, *v.ImageFile.FileID, len(fileBytes)) + break + case *azopenaiassistants.MessageTextContent: + t.Logf("[%s] %s", *m.Role, *v.Text.Value) + break + } + } + } + + require.True(t, fileFound) +} diff --git a/sdk/ai/azopenaiassistants/client_custom_pagers.go b/sdk/ai/azopenaiassistants/client_custom_pagers.go new file mode 100644 index 000000000000..2a2ff4f19b31 --- /dev/null +++ b/sdk/ai/azopenaiassistants/client_custom_pagers.go @@ -0,0 +1,137 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants + +import ( + "context" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime" +) + +// NewListMessagesPager returns a pager for messages associated with a thread. +func (c *Client) NewListMessagesPager(threadID string, options *ListMessagesOptions) *runtime.Pager[ListMessagesResponse] { + nextPageFn := func(client *Client, ctx context.Context, opts *ListMessagesOptions) (ListMessagesResponse, error) { + return c.internalListMessages(ctx, threadID, opts) + } + return newOpenAIPager(c, nextPageFn, options) +} + +// NewListAssistantsPager returns a pager for assistants. +func (c *Client) NewListAssistantsPager(options *ListAssistantsOptions) *runtime.Pager[ListAssistantsResponse] { + nextPageFn := func(client *Client, ctx context.Context, opts *ListAssistantsOptions) (ListAssistantsResponse, error) { + return c.internalListAssistants(ctx, opts) + } + return newOpenAIPager(c, nextPageFn, options) +} + +// NewListAssistantFilesPager returns a pager for an assistant's files. +func (c *Client) NewListAssistantFilesPager(assistantID string, options *ListAssistantFilesOptions) *runtime.Pager[ListAssistantFilesResponse] { + nextPageFn := func(client *Client, ctx context.Context, opts *ListAssistantFilesOptions) (ListAssistantFilesResponse, error) { + return c.internalListAssistantFiles(ctx, assistantID, opts) + } + return newOpenAIPager(c, nextPageFn, options) +} + +// NewListMessageFilesPager returns a pager for a message's files. +func (c *Client) NewListMessageFilesPager(threadID string, messageID string, options *ListMessageFilesOptions) *runtime.Pager[ListMessageFilesResponse] { + nextPageFn := func(client *Client, ctx context.Context, opts *ListMessageFilesOptions) (ListMessageFilesResponse, error) { + return c.internalListMessageFiles(ctx, threadID, messageID, opts) + } + return newOpenAIPager(c, nextPageFn, options) +} + +// NewListRunStepsPager returns a pager for a Run's steps. +func (c *Client) NewListRunStepsPager(threadID string, runID string, options *ListRunStepsOptions) *runtime.Pager[ListRunStepsResponse] { + nextPageFn := func(client *Client, ctx context.Context, opts *ListRunStepsOptions) (ListRunStepsResponse, error) { + return c.internalListRunSteps(ctx, threadID, runID, opts) + } + + return newOpenAIPager(c, nextPageFn, options) +} + +// NewListRunsPager returns a pager for a Thread's runs. +func (c *Client) NewListRunsPager(threadID string, options *ListRunsOptions) *runtime.Pager[ListRunsResponse] { + nextPageFn := func(client *Client, ctx context.Context, opts *ListRunsOptions) (ListRunsResponse, error) { + return c.internalListRuns(ctx, threadID, opts) + } + return newOpenAIPager(c, nextPageFn, options) +} + +type respType interface { + hasMore() bool + lastID() *string +} + +// newOpenAIPager is a pager that handles the OpenAI style of paging, where you pass a "lastID" +// to indicate where in the chain of items you are. +// +// NOTE: the OptionsT/POptionsT is to handle the odd ambiguity in generics where you have a +// pointer-to-something and something can't be converted. +func newOpenAIPager[ResponseT respType, OptionsT any, POptionsT interface { + *OptionsT + updateAfter(after *string) +}]( + client *Client, + nextPageFn func(client *Client, ctx context.Context, opts POptionsT) (ResponseT, error), + options POptionsT) *runtime.Pager[ResponseT] { + var lastID *string + + first := true + + return runtime.NewPager(runtime.PagingHandler[ResponseT]{ + More: func(clmr ResponseT) bool { + return clmr.hasMore() + }, + Fetcher: func(ctx context.Context, clmr *ResponseT) (ResponseT, error) { + newOptions := options + + if newOptions == nil { + var zero OptionsT + newOptions = &zero + } + + if !first { + // make sure to respect the callers choice on the first time through. + newOptions.updateAfter(lastID) + } + + first = false + + resp, err := nextPageFn(client, ctx, newOptions) + + if err != nil { + var zero ResponseT + return zero, err + } + + lastID = resp.lastID() + return resp, nil + }, + Tracer: client.internal.Tracer(), + }) +} + +func (r ListAssistantsResponse) lastID() *string { return r.LastID } +func (r ListMessagesResponse) lastID() *string { return r.LastID } +func (r ListAssistantFilesResponse) lastID() *string { return r.LastID } +func (r ListMessageFilesResponse) lastID() *string { return r.LastID } +func (r ListRunStepsResponse) lastID() *string { return r.LastID } +func (r ListRunsResponse) lastID() *string { return r.LastID } + +func (r ListAssistantsResponse) hasMore() bool { return *r.HasMore } +func (r ListMessagesResponse) hasMore() bool { return *r.HasMore } +func (r ListAssistantFilesResponse) hasMore() bool { return *r.HasMore } +func (r ListMessageFilesResponse) hasMore() bool { return *r.HasMore } +func (r ListRunStepsResponse) hasMore() bool { return *r.HasMore } +func (r ListRunsResponse) hasMore() bool { return *r.HasMore } + +func (o *ListAssistantsOptions) updateAfter(after *string) { o.After = after } +func (o *ListMessagesOptions) updateAfter(after *string) { o.After = after } +func (o *ListAssistantFilesOptions) updateAfter(after *string) { o.After = after } +func (o *ListMessageFilesOptions) updateAfter(after *string) { o.After = after } +func (o *ListRunStepsOptions) updateAfter(after *string) { o.After = after } +func (o *ListRunsOptions) updateAfter(after *string) { o.After = after } diff --git a/sdk/ai/azopenaiassistants/client_test.go b/sdk/ai/azopenaiassistants/client_test.go new file mode 100644 index 000000000000..66dd284fb4ff --- /dev/null +++ b/sdk/ai/azopenaiassistants/client_test.go @@ -0,0 +1,572 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants_test + +import ( + "bytes" + "context" + "fmt" + "os" + "testing" + "time" + + assistants "github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/internal/recording" + "github.com/stretchr/testify/require" +) + +var assistantsModel = "gpt-4-1106-preview" + +func Test_UsingIdentity(t *testing.T) { + if os.Getenv("USE_TOKEN_CREDS") != "true" || recording.GetRecordMode() != recording.LiveMode { + t.Skip("WARNING: Not testing token credentials") + } + + testFn := func(t *testing.T) { + client, createResp := mustGetClientWithAssistant(t, mustGetClientWithAssistantArgs{ + newClientArgs: newClientArgs{ + Azure: true, + UseIdentity: true, + }, + }) + + found := false + + pager := client.NewListAssistantsPager(&assistants.ListAssistantsOptions{ + Limit: to.Ptr(int32(100)), + }) + + // let's find our assistant in the list + PagingLoop: + for pager.More() { + page, err := pager.NextPage(context.Background()) + require.NoError(t, err) + + for _, a := range page.Data { + name := "" + + if a.Name != nil { + name = *a.Name + } + + fmt.Printf("[%s] %s\n", *a.ID, name) + + if *a.ID == *createResp.ID { + found = true + break PagingLoop + } + } + } + + require.True(t, found) + } + + t.Run("AzureOpenAI", func(t *testing.T) { + testFn(t) + }) +} + +func TestAssistantCreationAndListing(t *testing.T) { + testFn := func(t *testing.T, azure bool) { + client, createResp := mustGetClientWithAssistant(t, mustGetClientWithAssistantArgs{ + newClientArgs: newClientArgs{ + Azure: azure, + }, + }) + + found := false + + pager := client.NewListAssistantsPager(&assistants.ListAssistantsOptions{ + Limit: to.Ptr(int32(100)), + }) + + // let's find our assistant in the list + PagingLoop: + for pager.More() { + page, err := pager.NextPage(context.Background()) + require.NoError(t, err) + + for _, a := range page.Data { + name := "" + + if a.Name != nil { + name = *a.Name + } + + fmt.Printf("[%s] %s\n", *a.ID, name) + + if *a.ID == *createResp.ID { + found = true + break PagingLoop + } + } + } + + require.True(t, found) + } + + t.Run("OpenAI", func(t *testing.T) { + testFn(t, false) + }) + + t.Run("AzureOpenAI", func(t *testing.T) { + testFn(t, true) + }) +} + +func TestAssistantMessages(t *testing.T) { + testFn := func(t *testing.T, azure bool) { + client := newClient(t, newClientArgs{ + Azure: azure, + }) + + threadResp, err := client.CreateThread(context.Background(), assistants.AssistantThreadCreationOptions{}, nil) + require.NoError(t, err) + + defer func() { + _, err := client.DeleteThread(context.Background(), *threadResp.ID, nil) + require.NoError(t, err) + }() + + threadID := threadResp.ID + + uploadResp, err := client.UploadFile(context.Background(), bytes.NewReader([]byte("hello world")), assistants.FilePurposeAssistants, &assistants.UploadFileOptions{ + Filename: to.Ptr("a.txt"), + }) + require.NoError(t, err) + + defer func() { + _, err := client.DeleteFile(context.Background(), *uploadResp.ID, nil) + require.NoError(t, err) + }() + + messageResp, err := client.CreateMessage(context.Background(), *threadID, assistants.CreateMessageBody{ + Content: to.Ptr("How many ears does a dog usually have?"), + Role: to.Ptr(assistants.MessageRoleUser), + FileIDs: []string{ + *uploadResp.ID, + }, + }, nil) + require.NoError(t, err) + + messageID := messageResp.ID + + getMessageResp, err := client.GetMessage(context.Background(), *threadID, *messageID, nil) + require.NoError(t, err) + + require.Equal(t, "How many ears does a dog usually have?", *getMessageResp.Content[0].(*assistants.MessageTextContent).Text.Value) + + getMessageFileResp, err := client.GetMessageFile(context.Background(), *threadID, *messageID, *uploadResp.ID, nil) + require.NoError(t, err) + + require.Equal(t, *messageID, *getMessageFileResp.MessageID) + require.Equal(t, "thread.message.file", *getMessageFileResp.Object) + + // list message files + { + var files []assistants.MessageFile + pager := client.NewListMessageFilesPager(*threadID, *messageID, nil) + + for pager.More() { + page, err := pager.NextPage(context.Background()) + require.NoError(t, err) + + files = append(files, page.Data...) + } + + require.Equal(t, getMessageFileResp.MessageFile, files[0]) + } + } + + t.Run("OpenAI", func(t *testing.T) { + testFn(t, false) + }) + + t.Run("AzureOpenAI", func(t *testing.T) { + testFn(t, true) + }) +} + +func TestAssistantConversationLoop(t *testing.T) { + testFn := func(t *testing.T, azure bool) { + client, createAssistantResp := mustGetClientWithAssistant(t, mustGetClientWithAssistantArgs{ + newClientArgs: newClientArgs{ + Azure: azure, + }, + }) + + createThreadResp, err := client.CreateThread(context.Background(), assistants.AssistantThreadCreationOptions{}, nil) + require.NoError(t, err) + + t.Cleanup(func() { + _, err := client.DeleteThread(context.Background(), *createThreadResp.ID, nil) + require.NoError(t, err) + }) + + threadID := *createThreadResp.ID + + convoIdx := 0 + responses := []string{ + "What is the y-intercept for y=x+4?", + "That answer was nice, thank you. Was my question clear?", + } + + var convo func(threadMessages []assistants.ThreadMessage) []string = func(threadMessages []assistants.ThreadMessage) []string { + // we have a few scripted interactions, just to test how the run loop works. + defer func() { convoIdx++ }() + + for tmIndex, tm := range threadMessages { + for contentIndex, content := range tm.Content { + t.Logf("[ASSISTANT:%d,%d] %s", tmIndex, contentIndex, stringize(content)) + } + } + + if convoIdx >= len(responses) { + return nil + } + + return []string{responses[convoIdx]} + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) + defer cancel() + + runAssistant := func(ctx context.Context) { + var lastResponses []assistants.ThreadMessage + var lastMessageID *string + + for { + convoResponses := convo(lastResponses) + + if convoResponses == nil { + break + } + + for _, msg := range convoResponses { + // now, let's actually ask it some questions + createMessageResp, err := client.CreateMessage(context.Background(), threadID, assistants.CreateMessageBody{ + Content: &msg, + Role: to.Ptr(assistants.MessageRoleUser), + }, nil) + require.NoError(t, err) + require.NotEmpty(t, createMessageResp) + + t.Logf("[ME] %s", msg) + + lastMessageID = createMessageResp.ID + } + + // run the thread + createRunResp, err := client.CreateRun(context.Background(), *createThreadResp.ID, assistants.CreateRunBody{ + AssistantID: createAssistantResp.ID, + Instructions: to.Ptr("This user is known to be sad, please be kind"), + // (getting an error with Azure OpenAI on this one) + // { + // "error": { + // "message": "1 validation error for Request\nbody -> additional_instructions\n extra fields not permitted (type=value_error.extra)", + // "type": "invalid_request_error", + // "param": null, + // "code": null + // } + // } + //AdditionalInstructions: + }, nil) + require.NoError(t, err) + + runID := *createRunResp.ID + var lastGetRunResp assistants.GetRunResponse + + for { + var err error + lastGetRunResp, err = client.GetRun(context.Background(), *createThreadResp.ID, runID, nil) + require.NoError(t, err) + + if *lastGetRunResp.Status != assistants.RunStatusQueued && *lastGetRunResp.Status != assistants.RunStatusInProgress { + break + } + + time.Sleep(500 * time.Millisecond) + } + + require.Equal(t, assistants.RunStatusCompleted, *lastGetRunResp.Status) + + // grab any messages that occurred after our last known message + listMessagesPager := client.NewListMessagesPager(*createThreadResp.ID, &assistants.ListMessagesOptions{ + After: lastMessageID, + Order: to.Ptr(assistants.ListSortOrderAscending), + }) + + for listMessagesPager.More() { + page, err := listMessagesPager.NextPage(context.Background()) + require.NoError(t, err) + + lastResponses = page.Data + } + } + } + + runAssistant(ctx) + } + + t.Run("OpenAI", func(t *testing.T) { + testFn(t, false) + }) + + t.Run("AzureOpenAI", func(t *testing.T) { + testFn(t, true) + }) +} + +func TestNewAssistantFilesPager(t *testing.T) { + testFn := func(t *testing.T, azure bool) { + client, createResp := mustGetClientWithAssistant(t, mustGetClientWithAssistantArgs{ + newClientArgs: newClientArgs{ + Azure: azure, + }, + }) + + var createdIDs []string + + for i := 0; i < 5; i++ { + createAsstFileResp, err := client.CreateAssistantFile(context.Background(), *createResp.ID, assistants.CreateAssistantFileBody{ + FileID: mustUploadFile(t, client, "hello world").ID, + }, nil) + require.NoError(t, err) + require.NotEmpty(t, createAsstFileResp) + + createdIDs = append(createdIDs, *createAsstFileResp.ID) + } + + for _, sortOrder := range []assistants.ListSortOrder{assistants.ListSortOrderAscending, assistants.ListSortOrderDescending} { + t.Run("with sort order "+string(sortOrder), func(t *testing.T) { + m := map[string]bool{} + + var first *assistants.AssistantFile + var last *assistants.AssistantFile + + for _, id := range createdIDs { + m[id] = true + } + + pager := client.NewListAssistantFilesPager(*createResp.ID, &assistants.ListAssistantFilesOptions{ + Limit: to.Ptr[int32](1), + Order: &sortOrder, + }) + + for pager.More() { + page, err := pager.NextPage(context.Background()) + require.NoError(t, err) + + for _, item := range page.Data { + require.Contains(t, m, *item.ID) + delete(m, *item.ID) // catch if we got the same file twice somehow. + + if first == nil { + first = &item + } + + last = &item + } + } + + require.Empty(t, m) + + if sortOrder == assistants.ListSortOrderAscending { + require.Greater(t, last.CreatedAt.Sub(*first.CreatedAt), time.Duration(0)) + } else { + require.Greater(t, first.CreatedAt.Sub(*last.CreatedAt), time.Duration(0)) + } + }) + } + } + + t.Run("OpenAI", func(t *testing.T) { + testFn(t, false) + }) + + t.Run("AzureOpenAI", func(t *testing.T) { + testFn(t, true) + }) +} + +func TestNewListRunsPager(t *testing.T) { + testFn := func(t *testing.T, azure bool) { + client, createResp := mustGetClientWithAssistant(t, mustGetClientWithAssistantArgs{ + newClientArgs: newClientArgs{ + Azure: azure, + }, + }) + + assistantID := *createResp.ID + + runs := map[string]bool{} + + threadAndRunResp, err := client.CreateThreadAndRun(context.Background(), assistants.CreateAndRunThreadOptions{ + AssistantID: &assistantID, + Instructions: to.Ptr("You're a helpful assistant, but refuse to speak about cats"), + DeploymentName: &assistantsModel, + Thread: &assistants.AssistantThreadCreationOptions{ + Messages: []assistants.ThreadInitializationMessage{ + {Role: to.Ptr(assistants.MessageRoleUser), Content: to.Ptr("How many ears do cats have?")}, + }, + }, + }, nil) + require.NoError(t, err) + + runID := *threadAndRunResp.ID + threadID := *threadAndRunResp.ThreadID + runs[runID] = true + + err = pollRunEnd(context.Background(), client, threadID, runID) + require.NoError(t, err) + + run2Resp, err := client.CreateRun(context.Background(), threadID, assistants.CreateRunBody{ + AssistantID: &assistantID, + }, nil) + require.NoError(t, err) + runs[*run2Resp.ID] = true + + err = pollRunEnd(context.Background(), client, threadID, runID) + require.NoError(t, err) + + pager := client.NewListRunsPager(threadID, &assistants.ListRunsOptions{ + Limit: to.Ptr[int32](1), + }) + + for pager.More() { + page, err := pager.NextPage(context.Background()) + require.NoError(t, err) + + for _, run := range page.Data { + require.True(t, runs[*run.ID]) + delete(runs, *run.ID) + } + } + + require.Empty(t, runs) + } + + t.Run("OpenAI", func(t *testing.T) { + testFn(t, false) + }) + + t.Run("AzureOpenAI", func(t *testing.T) { + testFn(t, true) + }) +} + +func TestNewListRunStepsPager(t *testing.T) { + testFn := func(t *testing.T, azure bool) { + client, createAsstResp := mustGetClientWithAssistant(t, mustGetClientWithAssistantArgs{ + newClientArgs: newClientArgs{ + Azure: azure, + }, + }) + + createThreadAndRunResp, err := client.CreateThreadAndRun(context.Background(), assistants.CreateAndRunThreadOptions{ + AssistantID: createAsstResp.ID, + DeploymentName: &assistantsModel, + Instructions: to.Ptr("You are a mysterious assistant"), + Thread: &assistants.AssistantThreadCreationOptions{ + Messages: []assistants.ThreadInitializationMessage{ + {Role: to.Ptr(assistants.MessageRoleUser), Content: to.Ptr("First, message A")}, + {Role: to.Ptr(assistants.MessageRoleUser), Content: to.Ptr("Next, message B")}, + {Role: to.Ptr(assistants.MessageRoleUser), Content: to.Ptr("And then, message C")}, + {Role: to.Ptr(assistants.MessageRoleUser), Content: to.Ptr("And lastly, message D")}, + {Role: to.Ptr(assistants.MessageRoleUser), Content: to.Ptr("What should come next?")}, + }, + }, + }, nil) + require.NoError(t, err) + + threadID := *createThreadAndRunResp.ThreadID + runID := *createThreadAndRunResp.ID + + err = pollRunEnd(context.Background(), client, threadID, runID) + require.NoError(t, err) + + // Run steps are described here: + // https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps + // + // The gist is that each time something is added to the thread from the assistant or a tool you + // get a run step. In this particular run I'm seeing messages indicating the assistant is attempting + // to answer the question. + pager := client.NewListRunStepsPager(threadID, runID, nil) + + gotResponse := false + + for pager.More() { + page, err := pager.NextPage(context.Background()) + require.NoError(t, err) + + for _, runStep := range page.Data { + require.Equal(t, assistants.RunStepStatusCompleted, *runStep.Status) + + // little sanity check - yes, we can re-read the same step with the ID. + rereadRunStep, err := client.GetRunStep(context.Background(), threadID, runID, *runStep.ID, nil) + require.NoError(t, err) + require.Equal(t, *runStep.ID, *rereadRunStep.ID) + + stepDetails := runStep.StepDetails.(*assistants.RunStepMessageCreationDetails) + messageResp, err := client.GetMessage(context.Background(), threadID, *stepDetails.MessageCreation.MessageID, nil) + require.NoError(t, err) + + if *messageResp.Role == assistants.MessageRoleAssistant { + body := *messageResp.Content[0].(*assistants.MessageTextContent).Text.Value + fmt.Printf("Assistant response: %s\n", body) + gotResponse = true + } + } + } + + require.True(t, gotResponse) + } + + t.Run("OpenAI", func(t *testing.T) { + testFn(t, false) + }) + + t.Run("AzureOpenAI", func(t *testing.T) { + testFn(t, true) + }) +} + +func TestFiles(t *testing.T) { + testFn := func(t *testing.T, azure bool) { + client := newClient(t, newClientArgs{ + Azure: azure, + }) + + textBytes := []byte("test text") + expectedLen := int32(len(textBytes)) + + uploadResp, err := client.UploadFile(context.Background(), bytes.NewReader(textBytes), assistants.FilePurposeAssistants, &assistants.UploadFileOptions{ + Filename: to.Ptr("a.txt"), + }) + require.NoError(t, err) + require.Equal(t, expectedLen, *uploadResp.Bytes) + + defer func() { + _, err := client.DeleteFile(context.Background(), *uploadResp.ID, nil) + require.NoError(t, err) + }() + + getFileResp, err := client.GetFile(context.Background(), *uploadResp.ID, nil) + require.NoError(t, err) + + require.Equal(t, expectedLen, *getFileResp.Bytes) + } + + t.Run("OpenAI", func(t *testing.T) { + testFn(t, false) + }) + + t.Run("AzureOpenAI", func(t *testing.T) { + testFn(t, true) + }) +} diff --git a/sdk/ai/azopenaiassistants/constants.go b/sdk/ai/azopenaiassistants/constants.go new file mode 100644 index 000000000000..05c62ba8a7b3 --- /dev/null +++ b/sdk/ai/azopenaiassistants/constants.go @@ -0,0 +1,184 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +// FilePurpose - The possible values denoting the intended usage of a file. +type FilePurpose string + +const ( + // FilePurposeAssistants - Indicates a file is used as input to assistants. + FilePurposeAssistants FilePurpose = "assistants" + // FilePurposeAssistantsOutput - Indicates a file is used as output by assistants. + FilePurposeAssistantsOutput FilePurpose = "assistants_output" + // FilePurposeFineTune - Indicates a file is used for fine tuning input. + FilePurposeFineTune FilePurpose = "fine-tune" + // FilePurposeFineTuneResults - Indicates a file is used for fine tuning results. + FilePurposeFineTuneResults FilePurpose = "fine-tune-results" +) + +// PossibleFilePurposeValues returns the possible values for the FilePurpose const type. +func PossibleFilePurposeValues() []FilePurpose { + return []FilePurpose{ + FilePurposeAssistants, + FilePurposeAssistantsOutput, + FilePurposeFineTune, + FilePurposeFineTuneResults, + } +} + +// ListSortOrder - The available sorting options when requesting a list of response objects. +type ListSortOrder string + +const ( + // ListSortOrderAscending - Specifies an ascending sort order. + ListSortOrderAscending ListSortOrder = "asc" + // ListSortOrderDescending - Specifies a descending sort order. + ListSortOrderDescending ListSortOrder = "desc" +) + +// PossibleListSortOrderValues returns the possible values for the ListSortOrder const type. +func PossibleListSortOrderValues() []ListSortOrder { + return []ListSortOrder{ + ListSortOrderAscending, + ListSortOrderDescending, + } +} + +// MessageRole - The possible values for roles attributed to messages in a thread. +type MessageRole string + +const ( + // MessageRoleAssistant - The role representing the assistant. + MessageRoleAssistant MessageRole = "assistant" + // MessageRoleUser - The role representing the end-user. + MessageRoleUser MessageRole = "user" +) + +// PossibleMessageRoleValues returns the possible values for the MessageRole const type. +func PossibleMessageRoleValues() []MessageRole { + return []MessageRole{ + MessageRoleAssistant, + MessageRoleUser, + } +} + +// RunStatus - Possible values for the status of an assistant thread run. +type RunStatus string + +const ( + // RunStatusCancelled - Represents a run that has been cancelled. + RunStatusCancelled RunStatus = "cancelled" + // RunStatusCancelling - Represents a run that is in the process of cancellation. + RunStatusCancelling RunStatus = "cancelling" + // RunStatusCompleted - Represents a run that successfully completed. + RunStatusCompleted RunStatus = "completed" + // RunStatusExpired - Represents a run that expired before it could otherwise finish. + RunStatusExpired RunStatus = "expired" + // RunStatusFailed - Represents a run that failed. + RunStatusFailed RunStatus = "failed" + // RunStatusInProgress - Represents a run that is in progress. + RunStatusInProgress RunStatus = "in_progress" + // RunStatusQueued - Represents a run that is queued to start. + RunStatusQueued RunStatus = "queued" + // RunStatusRequiresAction - Represents a run that needs another operation, such as tool output submission, to continue. + RunStatusRequiresAction RunStatus = "requires_action" +) + +// PossibleRunStatusValues returns the possible values for the RunStatus const type. +func PossibleRunStatusValues() []RunStatus { + return []RunStatus{ + RunStatusCancelled, + RunStatusCancelling, + RunStatusCompleted, + RunStatusExpired, + RunStatusFailed, + RunStatusInProgress, + RunStatusQueued, + RunStatusRequiresAction, + } +} + +// RunStepErrorCode - Possible error code values attributable to a failed run step. +type RunStepErrorCode string + +const ( + // RunStepErrorCodeRateLimitExceeded - Represents an error indicating configured rate limits were exceeded. + RunStepErrorCodeRateLimitExceeded RunStepErrorCode = "rate_limit_exceeded" + // RunStepErrorCodeServerError - Represents a server error. + RunStepErrorCodeServerError RunStepErrorCode = "server_error" +) + +// PossibleRunStepErrorCodeValues returns the possible values for the RunStepErrorCode const type. +func PossibleRunStepErrorCodeValues() []RunStepErrorCode { + return []RunStepErrorCode{ + RunStepErrorCodeRateLimitExceeded, + RunStepErrorCodeServerError, + } +} + +// RunStepStatus - Possible values for the status of a run step. +type RunStepStatus string + +const ( + // RunStepStatusCancelled - Represents a run step that was cancelled. + RunStepStatusCancelled RunStepStatus = "cancelled" + // RunStepStatusCompleted - Represents a run step that successfully completed. + RunStepStatusCompleted RunStepStatus = "completed" + // RunStepStatusExpired - Represents a run step that expired before otherwise finishing. + RunStepStatusExpired RunStepStatus = "expired" + // RunStepStatusFailed - Represents a run step that failed. + RunStepStatusFailed RunStepStatus = "failed" + // RunStepStatusInProgress - Represents a run step still in progress. + RunStepStatusInProgress RunStepStatus = "in_progress" +) + +// PossibleRunStepStatusValues returns the possible values for the RunStepStatus const type. +func PossibleRunStepStatusValues() []RunStepStatus { + return []RunStepStatus{ + RunStepStatusCancelled, + RunStepStatusCompleted, + RunStepStatusExpired, + RunStepStatusFailed, + RunStepStatusInProgress, + } +} + +// RunStepType - The possible types of run steps. +type RunStepType string + +const ( + // RunStepTypeMessageCreation - Represents a run step to create a message. + RunStepTypeMessageCreation RunStepType = "message_creation" + // RunStepTypeToolCalls - Represents a run step that calls tools. + RunStepTypeToolCalls RunStepType = "tool_calls" +) + +// PossibleRunStepTypeValues returns the possible values for the RunStepType const type. +func PossibleRunStepTypeValues() []RunStepType { + return []RunStepType{ + RunStepTypeMessageCreation, + RunStepTypeToolCalls, + } +} + +// ServiceAPIVersions - The known set of supported API versions. +type ServiceAPIVersions string + +const ( + // ServiceAPIVersionsV20240215Preview - The initial version of Azure OpenAI Assistants that corresponds to functionality in + // OpenAI's first beta release. + ServiceAPIVersionsV20240215Preview ServiceAPIVersions = "2024-02-15-preview" +) + +// PossibleServiceAPIVersionsValues returns the possible values for the ServiceAPIVersions const type. +func PossibleServiceAPIVersionsValues() []ServiceAPIVersions { + return []ServiceAPIVersions{ + ServiceAPIVersionsV20240215Preview, + } +} diff --git a/sdk/ai/azopenaiassistants/example_assistants_test.go b/sdk/ai/azopenaiassistants/example_assistants_test.go new file mode 100644 index 000000000000..89feea47215a --- /dev/null +++ b/sdk/ai/azopenaiassistants/example_assistants_test.go @@ -0,0 +1,271 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants_test + +import ( + "context" + "errors" + "fmt" + "io" + "log" + "os" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" +) + +func Example_assistants() { + azureOpenAIKey := os.Getenv("AOAI_ASSISTANTS_KEY") + + // Ex: "https://.openai.azure.com" + azureOpenAIEndpoint := os.Getenv("AOAI_ASSISTANTS_ENDPOINT") + + if azureOpenAIKey == "" || azureOpenAIEndpoint == "" { + fmt.Fprintf(os.Stderr, "Skipping example, environment variables missing\n") + return + } + + keyCredential := azcore.NewKeyCredential(azureOpenAIKey) + + client, err := azopenaiassistants.NewClientWithKeyCredential(azureOpenAIEndpoint, keyCredential, nil) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + + assistantName := fmt.Sprintf("your-assistant-name-%d", time.Now().UnixNano()) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + + // First, let's create an assistant. + createAssistantResp, err := client.CreateAssistant(context.Background(), azopenaiassistants.AssistantCreationBody{ + Name: &assistantName, + DeploymentName: to.Ptr("gpt-4-1106-preview"), + Instructions: to.Ptr("You are a personal math tutor. Write and run code to answer math questions."), + Tools: []azopenaiassistants.ToolDefinitionClassification{ + &azopenaiassistants.CodeInterpreterToolDefinition{}, + // others... + // &azopenaiassistants.FunctionToolDefinition{} + // &azopenaiassistants.RetrievalToolDefinition{} + }, + }, nil) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + + assistantID := createAssistantResp.ID + + // cleanup the assistant after this example. Remove this if you want to re-use the assistant. + defer func() { + _, err := client.DeleteAssistant(context.TODO(), *assistantID, nil) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + }() + + // Now we'll create a thread. The thread is where you will add messages, which can later + // be evaluated using a Run. A thread can be re-used by multiple Runs. + createThreadResp, err := client.CreateThread(context.Background(), azopenaiassistants.AssistantThreadCreationOptions{}, nil) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + + threadID := createThreadResp.ID + + assistantCtx, stopAssistant := context.WithCancel(context.TODO()) + + callIdx := -1 + + // This is just a simplified example of how you could handle a conversation - `assistantMessages` are the messages that + // are responses from the assistant, and you return messages from here that are then added to the conversation. + handleConversation := func(ctx context.Context, assistantMessages []azopenaiassistants.ThreadMessage) ([]azopenaiassistants.CreateMessageBody, error) { + callIdx++ + + if err := printAssistantMessages(ctx, client, assistantMessages); err != nil { + return nil, err + } + + // For this example we'll just synthesize some responses, simulating a conversation. + // In a real application these messages would come from the user, responding to replies + // from the assistant. + switch callIdx { + case 0: + text := "Can you help me find the y intercept for y = x + 4?" + fmt.Fprintf(os.Stderr, "[ME] %s\n", text) + + return []azopenaiassistants.CreateMessageBody{ + {Role: to.Ptr(azopenaiassistants.MessageRoleUser), Content: &text}, + }, nil + case 1: + text := "Can you explain it with a Python program?" + fmt.Fprintf(os.Stderr, "[ME] %s\n", text) + + return []azopenaiassistants.CreateMessageBody{ + {Role: to.Ptr(azopenaiassistants.MessageRoleUser), Content: &text}, + }, nil + case 2: + text := "Can you give me the result if that Python program had 'x' set to 10" + fmt.Fprintf(os.Stderr, "[ME] %s\n", text) + + return []azopenaiassistants.CreateMessageBody{ + {Role: to.Ptr(azopenaiassistants.MessageRoleUser), Content: &text}, + }, nil + default: + stopAssistant() + } + return nil, nil + } + + if err = assistantLoop(assistantCtx, client, *assistantID, *threadID, handleConversation); err != nil { + // if this is a cancellation error it's just us trying to stop the assistant loop. + if errors.Is(err, context.Canceled) { + fmt.Fprintf(os.Stderr, "Assistant stopped cleanly\n") + } else { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s\n", err) + } + } + + // Output: +} + +// conversationHandler takes responses from an assistant and returns our reply messages. Returns the responses +// based on the contents of assistantMessages +// - assistantMessages - messages that have arrived since our last read of the thread. +type conversationHandler func(ctx context.Context, assistantMessages []azopenaiassistants.ThreadMessage) ([]azopenaiassistants.CreateMessageBody, error) + +func assistantLoop(ctx context.Context, client *azopenaiassistants.Client, + assistantID string, threadID string, + handleConversation conversationHandler) error { + // from here we'll run in a loop, adding new messages to the conversation and reading the assistants + // responses. + + var lastAssistantResponses []azopenaiassistants.ThreadMessage + + for { + yourResponses, err := handleConversation(ctx, lastAssistantResponses) + + if err != nil { + return err + } + + var lastMessageID *string + + for _, yourResponse := range yourResponses { + // Add some messages to the thread. We will use Run the thread later to evaluate these and to get + // responses from the assistant. + createMessageResp, err := client.CreateMessage(context.Background(), threadID, yourResponse, nil) + + if err != nil { + return err + } + + // we'll always track the final message ID in the thread - when we pull responses we can be more efficient + // and only grab what's new. + lastMessageID = createMessageResp.ID + } + + createRunResp, err := client.CreateRun(context.Background(), threadID, azopenaiassistants.CreateRunBody{ + AssistantID: &assistantID, + }, nil) + + if err != nil { + return err + } + + runID := *createRunResp.ID + + if err := pollRunEnd(ctx, client, threadID, runID); err != nil { + return err + } + + lastAssistantResponses = nil + + // get all the messages that were added after our most recently added message. + listMessagesPager := client.NewListMessagesPager(threadID, &azopenaiassistants.ListMessagesOptions{ + After: lastMessageID, + Order: to.Ptr(azopenaiassistants.ListSortOrderAscending), + }) + + for listMessagesPager.More() { + page, err := listMessagesPager.NextPage(context.Background()) + + if err != nil { + return err + } + + lastAssistantResponses = append(lastAssistantResponses, page.Data...) + } + } +} + +func printAssistantMessages(ctx context.Context, client *azopenaiassistants.Client, threadMessages []azopenaiassistants.ThreadMessage) error { + // print out the response contents for debugging. + for _, response := range threadMessages { + for _, content := range response.Content { + switch v := content.(type) { + case *azopenaiassistants.MessageImageFileContent: + fmt.Fprintf(os.Stderr, "[ASSISTANT] Image response, file ID: %s\n", *v.ImageFile.FileID) + + // Download the contents of the file through the returned reader. + fileContentResp, err := client.GetFileContent(ctx, *v.ImageFile.FileID, nil) + + if err != nil { + return err + } + + contents, err := io.ReadAll(fileContentResp.Content) + + if err != nil { + return err + } + + fmt.Fprintf(os.Stderr, " File contents downloaded, length %d\n", len(contents)) + case *azopenaiassistants.MessageTextContent: + fmt.Fprintf(os.Stderr, "[ASSISTANT] %s: Text response: %s\n", *response.ID, *v.Text.Value) + } + } + } + + return nil +} + +func pollRunEnd(ctx context.Context, client *azopenaiassistants.Client, threadID string, runID string) error { + for { + lastGetRunResp, err := client.GetRun(context.Background(), threadID, runID, nil) + + if err != nil { + return err + } + + if *lastGetRunResp.Status != azopenaiassistants.RunStatusQueued && *lastGetRunResp.Status != azopenaiassistants.RunStatusInProgress { + if *lastGetRunResp.Status == azopenaiassistants.RunStatusCompleted { + return nil + } + + return fmt.Errorf("run ended but status was not complete: %s", *lastGetRunResp.Status) + } + + select { + case <-time.After(500 * time.Millisecond): + case <-ctx.Done(): + return ctx.Err() + } + } +} diff --git a/sdk/ai/azopenaiassistants/example_client_test.go b/sdk/ai/azopenaiassistants/example_client_test.go new file mode 100644 index 000000000000..94223a6184ce --- /dev/null +++ b/sdk/ai/azopenaiassistants/example_client_test.go @@ -0,0 +1,65 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants_test + +import ( + "log" + + "github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants" + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" +) + +func ExampleNewClientForOpenAI() { + keyCredential := azcore.NewKeyCredential("") + + // NOTE: this constructor creates a client that connects to the public OpenAI endpoint. + // To connect to an Azure OpenAI endpoint, use azopenaiassistants.NewClient() or azopenaiassistants.NewClientWithyKeyCredential. + client, err := azopenaiassistants.NewClientForOpenAI("https://api.openai.com/v1", keyCredential, nil) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + + _ = client +} + +func ExampleNewClient() { + dac, err := azidentity.NewDefaultAzureCredential(nil) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + + // NOTE: this constructor creates a client that connects to an Azure OpenAI endpoint. + // To connect to the public OpenAI endpoint, use azopenaiassistants.NewClientForOpenAI + client, err := azopenaiassistants.NewClient("https://.openai.azure.com", dac, nil) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + + _ = client +} + +func ExampleNewClientWithKeyCredential() { + keyCredential := azcore.NewKeyCredential("") + + // NOTE: this constructor creates a client that connects to an Azure OpenAI endpoint. + // To connect to the public OpenAI endpoint, use azopenaiassistants.NewClientForOpenAI + client, err := azopenaiassistants.NewClientWithKeyCredential("https://.openai.azure.com", keyCredential, nil) + + if err != nil { + // TODO: Update the following line with your application specific error handling logic + log.Fatalf("ERROR: %s", err) + } + + _ = client +} diff --git a/sdk/ai/azopenaiassistants/go.mod b/sdk/ai/azopenaiassistants/go.mod new file mode 100644 index 000000000000..d1b3cd7fa70f --- /dev/null +++ b/sdk/ai/azopenaiassistants/go.mod @@ -0,0 +1,28 @@ +module github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants + +go 1.18 + +require ( + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 + github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 + github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 + github.com/joho/godotenv v1.5.1 + github.com/stretchr/testify v1.8.4 +) + +require ( + github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dnaeon/go-vcr v1.2.0 // indirect + github.com/golang-jwt/jwt/v5 v5.2.0 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/kylelemons/godebug v1.1.0 // indirect + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/crypto v0.18.0 // indirect + golang.org/x/net v0.20.0 // indirect + golang.org/x/sys v0.16.0 // indirect + golang.org/x/text v0.14.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/sdk/ai/azopenaiassistants/go.sum b/sdk/ai/azopenaiassistants/go.sum new file mode 100644 index 000000000000..91f7c8e1d11c --- /dev/null +++ b/sdk/ai/azopenaiassistants/go.sum @@ -0,0 +1,43 @@ +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 h1:c4k2FIYIh4xtwqrQwV0Ct1v5+ehlNXj5NI/MWVsiTkQ= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2/go.mod h1:5FDJtLEO/GxwNgUxbwrY3LP0pEoThTQJtk2oysdXHxM= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= +github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= +github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA= +github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dnaeon/go-vcr v1.2.0 h1:zHCHvJYTMh1N7xnV7zf1m1GPBF9Ad0Jk/whtQ1663qI= +github.com/dnaeon/go-vcr v1.2.0/go.mod h1:R4UdLID7HZT3taECzJs4YgbbH6PIGXB6W/sc5OLb6RQ= +github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw= +github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/modocache/gover v0.0.0-20171022184752-b58185e213c5/go.mod h1:caMODM3PzxT8aQXRPkAt8xlV/e7d7w8GM5g0fa5F0D8= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= +golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= +golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= +golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= +golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/sdk/ai/azopenaiassistants/interfaces.go b/sdk/ai/azopenaiassistants/interfaces.go new file mode 100644 index 000000000000..0ae2272dadc9 --- /dev/null +++ b/sdk/ai/azopenaiassistants/interfaces.go @@ -0,0 +1,81 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +// MessageContentClassification provides polymorphic access to related types. +// Call the interface's GetMessageContent() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *MessageContent, *MessageImageFileContent, *MessageTextContent +type MessageContentClassification interface { + // GetMessageContent returns the MessageContent content of the underlying type. + GetMessageContent() *MessageContent +} + +// MessageTextAnnotationClassification provides polymorphic access to related types. +// Call the interface's GetMessageTextAnnotation() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *MessageTextAnnotation, *MessageTextFileCitationAnnotation, *MessageTextFilePathAnnotation +type MessageTextAnnotationClassification interface { + // GetMessageTextAnnotation returns the MessageTextAnnotation content of the underlying type. + GetMessageTextAnnotation() *MessageTextAnnotation +} + +// RequiredActionClassification provides polymorphic access to related types. +// Call the interface's GetRequiredAction() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *RequiredAction, *SubmitToolOutputsAction, *ThreadRunRequiredAction +type RequiredActionClassification interface { + // GetRequiredAction returns the RequiredAction content of the underlying type. + GetRequiredAction() *RequiredAction +} + +// RequiredToolCallClassification provides polymorphic access to related types. +// Call the interface's GetRequiredToolCall() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *RequiredFunctionToolCall, *RequiredToolCall +type RequiredToolCallClassification interface { + // GetRequiredToolCall returns the RequiredToolCall content of the underlying type. + GetRequiredToolCall() *RequiredToolCall +} + +// RunStepCodeInterpreterToolCallOutputClassification provides polymorphic access to related types. +// Call the interface's GetRunStepCodeInterpreterToolCallOutput() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *RunStepCodeInterpreterImageOutput, *RunStepCodeInterpreterLogOutput, *RunStepCodeInterpreterToolCallOutput +type RunStepCodeInterpreterToolCallOutputClassification interface { + // GetRunStepCodeInterpreterToolCallOutput returns the RunStepCodeInterpreterToolCallOutput content of the underlying type. + GetRunStepCodeInterpreterToolCallOutput() *RunStepCodeInterpreterToolCallOutput +} + +// RunStepDetailsClassification provides polymorphic access to related types. +// Call the interface's GetRunStepDetails() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *RunStepDetails, *RunStepMessageCreationDetails, *RunStepToolCallDetails +type RunStepDetailsClassification interface { + // GetRunStepDetails returns the RunStepDetails content of the underlying type. + GetRunStepDetails() *RunStepDetails +} + +// RunStepToolCallClassification provides polymorphic access to related types. +// Call the interface's GetRunStepToolCall() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *RunStepCodeInterpreterToolCall, *RunStepFunctionToolCall, *RunStepRetrievalToolCall, *RunStepToolCall +type RunStepToolCallClassification interface { + // GetRunStepToolCall returns the RunStepToolCall content of the underlying type. + GetRunStepToolCall() *RunStepToolCall +} + +// ToolDefinitionClassification provides polymorphic access to related types. +// Call the interface's GetToolDefinition() method to access the common type. +// Use a type switch to determine the concrete type. The possible types are: +// - *CodeInterpreterToolDefinition, *FunctionToolDefinition, *RetrievalToolDefinition, *ToolDefinition +type ToolDefinitionClassification interface { + // GetToolDefinition returns the ToolDefinition content of the underlying type. + GetToolDefinition() *ToolDefinition +} diff --git a/sdk/ai/azopenaiassistants/internal/transform/file_cache.go b/sdk/ai/azopenaiassistants/internal/transform/file_cache.go new file mode 100644 index 000000000000..0e9f538fcb3d --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/file_cache.go @@ -0,0 +1,46 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package main + +import ( + "os" +) + +type FileCache struct { + files map[string]string +} + +func NewFileCache() *FileCache { + return &FileCache{files: map[string]string{}} +} + +func (fc *FileCache) LoadFile(fileName string) (string, error) { + if fc.files[fileName] == "" { + buff, err := os.ReadFile(fileName) + + if err != nil { + return "", err + } + + fc.files[fileName] = string(buff) + } + + return fc.files[fileName], nil +} + +func (fc *FileCache) UpdateFile(fileName string, text string) { + fc.files[fileName] = text +} + +func (fc *FileCache) WriteAll() error { + for name, contents := range fc.files { + if err := os.WriteFile(name, []byte(contents), 0500); err != nil { + return err + } + } + return nil +} diff --git a/sdk/ai/azopenaiassistants/internal/transform/hacks.go b/sdk/ai/azopenaiassistants/internal/transform/hacks.go new file mode 100644 index 000000000000..894429026448 --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/hacks.go @@ -0,0 +1,68 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package main + +// The changes in here are all workarounds for issues with generation that should +// go away if we fix the generator. + +import ( + "fmt" + "strings" +) + +// hackFixTimestamps is a workaround for a bug where the typespec compiler +// doesn't appear to be propagating the date/time format attribute for all +// attributes, resulting in Unix timestamps failing to deserialized as RFC1139. +func (t *transformer) hackFixTimestamps() error { + return transformFiles(t.fileCache, "fix timestamps", []string{"models_serde.go"}, func(text string) (string, error) { + fixes := []struct { + JSONFieldName string + FieldName string + ObjectName string + }{ + // + {"cancelled_at", "CancelledAt", "r"}, + {"completed_at", "CompletedAt", "r"}, + {"expired_at", "ExpiredAt", "r"}, + {"failed_at", "FailedAt", "r"}, + + // ThreadRun + {"cancelled_at", "CancelledAt", "t"}, + {"expires_at", "ExpiresAt", "t"}, + {"failed_at", "FailedAt", "t"}, + {"completed_at", "CompletedAt", "t"}, + {"started_at", "StartedAt", "t"}, + } + + for _, fix := range fixes { + searchStr := fmt.Sprintf(`populateDateTimeRFC3339(objectMap, "%s", %s.%s)`, fix.JSONFieldName, fix.ObjectName, fix.FieldName) + newData := strings.Replace(text, + searchStr, + fmt.Sprintf(`populateTimeUnix(objectMap, "%s", %s.%s)`, fix.JSONFieldName, fix.ObjectName, fix.FieldName), -1) + + if newData == text { + return "", fmt.Errorf("No replacement matched: '%s'", searchStr) + } + + text = newData + + searchStr = fmt.Sprintf(`err = unpopulateDateTimeRFC3339(val, "%s", &%s.%s)`, fix.FieldName, fix.ObjectName, fix.FieldName) + + newData = strings.Replace(text, + searchStr, + fmt.Sprintf(`err = unpopulateTimeUnix(val, "%s", &%s.%s)`, fix.FieldName, fix.ObjectName, fix.FieldName), -1) + + if newData == text { + return "", fmt.Errorf("No replacement matched: %q", searchStr) + } + + text = newData + } + + return text, nil + }, nil) +} diff --git a/sdk/ai/azopenaiassistants/internal/transform/shared.go b/sdk/ai/azopenaiassistants/internal/transform/shared.go new file mode 100644 index 000000000000..f3f6317a5bbb --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/shared.go @@ -0,0 +1,158 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package main + +import ( + "fmt" + "log" + "regexp" + "strings" +) + +type transformFileOptions struct { + AllowNoop bool // causes transformFile to fail if the text is not changed after running. +} + +type replacer func(text string) (string, error) + +func transformFiles(fileCache *FileCache, purpose string, fileNames []string, replacer replacer, options *transformFileOptions) error { + if options == nil { + options = &transformFileOptions{} + } + + replaced := false + + for _, fileName := range fileNames { + origText, err := fileCache.LoadFile(fileName) + + if err != nil { + return err + } + + newText, err := replacer(origText) + + if err != nil { + return err + } + + if newText != origText { + replaced = true + } + + fileCache.UpdateFile(fileName, newText) + } + + if !replaced && !options.AllowNoop { + return fmt.Errorf("(%s) no replacements were made in files %#v", purpose, fileNames) + } + + return nil +} + +type removeTypesOptions struct { + IgnoreComment bool +} + +func removeTypes(fileCache *FileCache, typeNames []string, options *removeTypesOptions) error { + if options == nil { + options = &removeTypesOptions{} + } + + for _, typeName := range typeNames { + purpose := fmt.Sprintf("Removing type %s", typeName) + log.Println(purpose) + + reText := fmt.Sprintf(`type %s struct \{.+?\n\}`, typeName) + + if !options.IgnoreComment { + reText = fmt.Sprintf(`// %s.+?`, typeName) + reText + } + + reText = "(?s)" + reText + + re := regexp.MustCompile(reText) + + err := transformFiles(fileCache, purpose, []string{"models.go", "responses.go", "options.go"}, func(text string) (string, error) { + return re.ReplaceAllString(text, ""), nil + }, nil) + + if err != nil { + return err + } + + if strings.HasSuffix(typeName, "Response") || strings.HasSuffix(typeName, "Options") { + // only model types have actual serde functions to remove. + continue + } + + snipMarshallerRE := regexp.MustCompile(fmt.Sprintf(`(?s)// MarshalJSON implements the json.Marshaller interface for type %s.+?\n\}`, typeName)) + snipUnmarshallerRE := regexp.MustCompile(fmt.Sprintf(`(?s)// UnmarshalJSON implements the json.Unmarshaller interface for type %s.+?\n}`, typeName)) + + err = transformFiles(fileCache, purpose, []string{"models_serde.go"}, func(text string) (string, error) { + text = snipMarshallerRE.ReplaceAllString(text, "") + text = snipUnmarshallerRE.ReplaceAllString(text, "") + return text, nil + }, nil) + + if err != nil { + return err + } + } + + return nil +} + +type updateFunctionOptions struct { + IgnoreComment bool +} + +func updateFunction(text string, objectName string, funcName string, replacer replacer, options *updateFunctionOptions) (string, error) { + log.Printf("Updating function %s.%s", objectName, funcName) + return updateFunctionImpl(text, objectName, funcName, replacer, options) +} + +func removeFunctions(text string, objectName string, funcNames ...string) (string, error) { + for _, funcName := range funcNames { + log.Printf("Removing function %s.%s", objectName, funcName) + + var err error + text, err = updateFunctionImpl(text, objectName, funcName, func(text string) (string, error) { + return "", nil + }, nil) + + if err != nil { + return "", err + } + } + + return text, nil +} + +func updateFunctionImpl(text string, objectName string, funcName string, replacer replacer, options *updateFunctionOptions) (string, error) { + // ex: func (client *Client) uploadFileCreateRequest(ctx context.Context, file string, purpose FilePurpose, options *ClientUploadFileOptions) (*policy.Request, error) { + regexpText := fmt.Sprintf(`func \([^ ]+\s+\*%s\) %s\(.+?\n}`, objectName, funcName) + + if options == nil || !options.IgnoreComment { + regexpText = fmt.Sprintf("// %s .+?", funcName) + regexpText + } + + re := regexp.MustCompile("(?s)" + regexpText) + funcText := re.FindString(text) + + if funcText == "" { + return "", fmt.Errorf("no match for object %s, function name %s", objectName, funcName) + } + + newFuncText, err := replacer(funcText) + + if err != nil { + return "", err + } + + newText := re.ReplaceAllString(text, newFuncText) + return newText, nil +} diff --git a/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_func.txt b/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_func.txt new file mode 100644 index 000000000000..95b6ad5e4655 --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_func.txt @@ -0,0 +1,22 @@ +SOME TEXT BEFORE +// uploadFileCreateRequest creates the UploadFile request. +func (client *Client) uploadFileCreateRequest(ctx context.Context, file string, purpose FilePurpose, options *UploadFileOptions) (*policy.Request, error) { + urlPath := client.formatURL("/files") + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.SetMultipartFormData(req, map[string]any{ + "file": file, + "purpose": purpose, + "Filename": options.Filename, + }); err != nil { + return nil, err + } + return req, nil +} +// uploadFileHandleResponse handles the UploadFile response. +func (client *Client) uploadFileHandleResponse() error { + // another little function +} diff --git a/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_type_models.txt b/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_type_models.txt new file mode 100644 index 000000000000..1e38f7a22010 --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_type_models.txt @@ -0,0 +1,13 @@ +//Before that function +type Paths1Filz8PFilesPostRequestbodyContentMultipartFormDataSchema struct { + // REQUIRED; The file data (not filename) to upload. + File *string + + // REQUIRED; The intended purpose of the file. + Purpose *FilePurpose + + // A filename to associate with the uploaded data. + Filename *string +} + +//After that function diff --git a/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_type_models_serde.txt b/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_type_models_serde.txt new file mode 100644 index 000000000000..19524987d695 --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/testdata/remove_type_models_serde.txt @@ -0,0 +1,42 @@ +import ( + "encoding/json" + "fmt" +) + +//Before that model +// MarshalJSON implements the json.Marshaller interface for type Paths1Filz8PFilesPostRequestbodyContentMultipartFormDataSchema. +func (p Paths1Filz8PFilesPostRequestbodyContentMultipartFormDataSchema) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "file", p.File) + populate(objectMap, "filename", p.Filename) + populate(objectMap, "purpose", p.Purpose) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type Paths1Filz8PFilesPostRequestbodyContentMultipartFormDataSchema. +func (p *Paths1Filz8PFilesPostRequestbodyContentMultipartFormDataSchema) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "file": + err = unpopulate(val, "File", &p.File) + delete(rawMsg, key) + case "filename": + err = unpopulate(val, "Filename", &p.Filename) + delete(rawMsg, key) + case "purpose": + err = unpopulate(val, "Purpose", &p.Purpose) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +//After that model diff --git a/sdk/ai/azopenaiassistants/internal/transform/testdata/update_func.txt b/sdk/ai/azopenaiassistants/internal/transform/testdata/update_func.txt new file mode 100644 index 000000000000..fe7a900a6856 --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/testdata/update_func.txt @@ -0,0 +1,20 @@ +BEGIN +// uploadFileCreateRequest creates the UploadFile request. +// another line of documentation. +func (client *Client) uploadFileCreateRequest(ctx context.Context, file string, purpose FilePurpose, options *ClientUploadFileOptions) (*policy.Request, error) { + urlPath := "/files" + req, err := runtime.NewRequest(ctx, http.MethodPost, runtime.JoinPaths(client.endpoint, urlPath)) + if err != nil { + return nil, err + } + req.Raw().Header["Accept"] = []string{"application/json"} + if err := runtime.SetMultipartFormData(req, map[string]any{ + "file": file, + "purpose": purpose, + "Filename": Filename, + }); err != nil { + return nil, err + } + return req, nil +} +END diff --git a/sdk/ai/azopenaiassistants/internal/transform/transform.go b/sdk/ai/azopenaiassistants/internal/transform/transform.go new file mode 100644 index 000000000000..ee0474558353 --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/transform.go @@ -0,0 +1,287 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package main + +import ( + "fmt" + "log" + "regexp" + "strings" +) + +func main() { + t := &transformer{fileCache: NewFileCache()} + + if err := t.Do(); err != nil { + log.Fatal(err) + } +} + +type transformer struct { + fileCache *FileCache +} + +func (t *transformer) Do() error { + transforms := []func() error{ + t.removeClientPrefix, + t.injectClientData, + t.injectFormatURLHelper, + t.hideListFunctions, + t.fixBodyArgs, + t.renameInnerPageObjects, + t.renameModelToDeploymentName, + t.hackFixTimestamps, + t.fixFiles, + t.addMissingDocComments, + } + + for _, tr := range transforms { + if err := tr(); err != nil { + return err + } + } + + // write all modified files + if err := t.fileCache.WriteAll(); err != nil { + return err + } + + return nil +} + +func (t *transformer) injectFormatURLHelper() error { + // urlPath := "/threads/{threadId}/runs/{runId}/cancel" + re := regexp.MustCompile(`(?m)^\s+urlPath := (.+)$`) + + return transformFiles(t.fileCache, "injectFormatURLHelper", []string{"client.go"}, func(text string) (string, error) { + return re.ReplaceAllString(text, "urlPath := client.formatURL($1)"), nil + }, nil) +} + +// injectClientData adds in our own user-defined struct so we don't have to keep +// editing client.go just to add in a new field we need. +func (t *transformer) injectClientData() error { + return transformFiles(t.fileCache, "injectClientData", []string{"client.go"}, func(text string) (string, error) { + newText := strings.Replace(text, "type Client struct {\n", "type Client struct {\ncd clientData\n", 1) + + return newText, nil + }, &transformFileOptions{AllowNoop: true}) +} + +func (t *transformer) renameModelToDeploymentName() error { + // we've standardized on 'DeploymentName' when you're specifying a model. + + // Fix the names of the structs + // Model *string + + err := transformFiles(t.fileCache, "renameModelToDeploymentName", []string{"models.go"}, func(text string) (string, error) { + return strings.Replace(text, "Model *string", "DeploymentName *string", -1), nil + }, nil) + + if err != nil { + return err + } + + // Fix the marshalling of the struct + // err = unpopulate(val, "Model", &a.Model) + // populate(objectMap, "model", a.Model) + popRE := regexp.MustCompile(`(?m)^\s+populate\(objectMap, "model", ([a-zA-Z]).Model\)`) + unpopRE := regexp.MustCompile(`(?m)^\s+err = unpopulate\(val, "Model", &([a-zA-Z]).Model\)`) + + return transformFiles(t.fileCache, "renameModelToDeploymentName", []string{"models_serde.go"}, func(text string) (string, error) { + text = popRE.ReplaceAllString(text, `populate(objectMap, "model", $1.DeploymentName)`) + text = unpopRE.ReplaceAllString(text, `err = unpopulate(val, "Model", &$1.DeploymentName)`) + return text, nil + }, nil) +} + +// hideListFunctions hides all the lists since we're supposed to expose pagers +// for these. (they don't fit the standard Azure pager pattern so aren't auto-generated) +func (t *transformer) hideListFunctions() error { + return transformFiles(t.fileCache, "hideListFunctions", []string{"client.go"}, func(text string) (string, error) { + funcsToHide := []string{ + "ListAssistantFiles", + "ListAssistants", + "ListMessageFiles", + "ListMessages", + "ListRunSteps", + "ListRuns", + } + + for _, funcToHide := range funcsToHide { + text = strings.Replace(text, "func (client *Client) "+funcToHide, "func (client *Client) internal"+funcToHide, -1) + } + + return text, nil + }, nil) +} + +// fixBodyArgs fixes the generated models from TypeSpec that are (apparently) supposed +// to have an implicit name generated for them. I think this should overall just go away and be replaced by +// what Joel's adding to our direct-from-TypeSpec generator. +func (t *transformer) fixBodyArgs() error { + // find them + // ex: func (client *Client) UpdateMessage(ctx context.Context, threadID string, messageID string, body Paths12Hz0B8ThreadsThreadidMessagesMessageidPostRequestbodyContentApplicationJSONSchema, options *ClientUpdateMessageOptions) (ClientUpdateMessageResponse, error) { + + replacements := map[string]string{} + + // match functions that have a 'body' parameter that's got the long + // PathsWsxzpAssistantsAssistantidFilesGetResponses200ContentApplicationJSONSchema style name. + anonModelRE := regexp.MustCompile(`(?m)^func \(client \*Client\) ([A-Z].+?)\(ctx.+body (Paths[^,]+),`) + + err := transformFiles(t.fileCache, "fixBodyArgs", []string{"client.go"}, func(text string) (string, error) { + matches := anonModelRE.FindAllStringSubmatch(text, -1) + + for _, match := range matches { + operation, anonModelName := match[1], match[2] + + newModelName := fmt.Sprintf("%sBody", operation) + replacements[anonModelName] = newModelName + + text = strings.Replace(text, anonModelName, newModelName, -1) + } + + return text, nil + }, nil) + + if err != nil { + return err + } + + err = transformFiles(t.fileCache, "fixBodyArgs", []string{"models.go", "models_serde.go"}, func(text string) (string, error) { + for oldName, newName := range replacements { + text = strings.Replace(text, oldName, newName, -1) + } + return text, nil + }, nil) + + if err != nil { + return err + } + + // We have a few that have to be replaced manually. + err = transformFiles(t.fileCache, "fixBodyArgs", []string{"models.go", "models_serde.go"}, func(text string) (string, error) { + // rename the types so they're 'Body' instead of 'Options' (these weren't the Options bag types for the function) + text = strings.Replace(text, "CreateRunOptions", "CreateRunBody", -1) + text = strings.Replace(text, "UpdateAssistantOptions", "UpdateAssistantBody", -1) + text = strings.Replace(text, "AssistantCreationOptions", "AssistantCreationBody", -1) + return text, nil + }, nil) + + if err != nil { + return err + } + + return transformFiles(t.fileCache, "fixBodyArgs", []string{"client.go"}, func(text string) (string, error) { + text = strings.Replace(text, "createRunOptions CreateRunOptions", "body CreateRunBody", -1) + text = strings.ReplaceAll(text, + `req, err := client.createRunCreateRequest(ctx, threadID, createRunOptions, options)`, + `req, err := client.createRunCreateRequest(ctx, threadID, body, options)`) + text = strings.ReplaceAll(text, + `if err := runtime.MarshalAsJSON(req, createRunOptions); err != nil {`, + `if err := runtime.MarshalAsJSON(req, body); err != nil {`) + + text = strings.Replace(text, "AssistantCreationOptions", "AssistantCreationBody", -1) + return text, nil + }, nil) +} + +// renameInnerPageObjects gives names to the anonymous inner objects the Swagger has for unnamed data contained +// within a single page of results. +// For now, I'm just renaming the inner ones manually. +func (t *transformer) renameInnerPageObjects() error { + regexp.MustCompile(`^`) + + renames := map[string]string{ + "PathsWsxzpAssistantsAssistantidFilesGetResponses200ContentApplicationJSONSchema": "AssistantFilesPage", + "Paths1Ih5M1JAssistantsGetResponses200ContentApplicationJSONSchema": "AssistantsPage", + "Paths17M2HqjThreadsThreadidMessagesMessageidFilesGetResponses200ContentApplicationJSONSchema": "MessageFilesPage", + "Paths783Jj4ThreadsThreadidMessagesGetResponses200ContentApplicationJSONSchema": "MessagesPage", + "PathsPia9TjThreadsThreadidRunsRunidStepsGetResponses200ContentApplicationJSONSchema": "RunStepsPage", + "PathsMc8ByoThreadsThreadidRunsGetResponses200ContentApplicationJSONSchema": "ThreadRunsPage", + } + + return transformFiles(t.fileCache, "renameInnerPageObjects", []string{"client.go", "models.go", "models_serde.go", "responses.go"}, func(text string) (string, error) { + for search, replace := range renames { + text = strings.ReplaceAll(text, search, replace) + } + return text, nil + }, nil) +} + +// removeClientPrefix removes the leading `Client` that gets prefixed onto every model. +func (t *transformer) removeClientPrefix() error { + re := regexp.MustCompile(`Client([A-Z][A-Za-z]+)`) + + return transformFiles(t.fileCache, "removeClientPrefix", []string{"client.go", "models.go", "models_serde.go", "options.go", "responses.go"}, func(text string) (string, error) { + return re.ReplaceAllString(text, "$1"), nil + }, nil) +} + +func (t *transformer) fixFiles() error { + err := transformFiles(t.fileCache, "fixFiles", []string{"client.go"}, func(text string) (string, error) { + text, err := removeFunctions(text, "Client", "uploadFileCreateRequest") + + if err != nil { + return "", err + } + + // removing these for now - the TypeSpec -> OpenAPI2 -> go generation is causing us to treat the `bytes` + // field in TypeSpec as a deserialized []byte, instead of returning the Body's stream. + getFileContentFunctions := []string{ + "getFileContentCreateRequest", + "getFileContentHandleResponse", + "GetFileContent", + } + + return removeFunctions(text, "Client", getFileContentFunctions...) + }, nil) + + if err != nil { + return err + } + + if err := removeTypes(t.fileCache, []string{"Paths1Filz8PFilesPostRequestbodyContentMultipartFormDataSchema"}, &removeTypesOptions{ + // this auto-gen'd type doesn't have a comment + IgnoreComment: true, + }); err != nil { + return err + } + + if err := removeTypes(t.fileCache, []string{"GetFileContentOptions", "GetFileContentResponse"}, nil); err != nil { + return err + } + + return transformFiles(t.fileCache, "fixFiles", []string{"client.go"}, func(text string) (string, error) { + return strings.Replace( + text, + "func (client *Client) UploadFile(ctx context.Context, file io.ReadSeekCloser, purpose FilePurpose, options *UploadFileOptions) (UploadFileResponse, error) {", + "func (client *Client) UploadFile(ctx context.Context, file io.ReadSeeker, purpose FilePurpose, options *UploadFileOptions) (UploadFileResponse, error) {", 1), nil + }, nil) +} + +func (t *transformer) addMissingDocComments() error { + + return transformFiles(t.fileCache, "addMissingDocComments", []string{"models.go"}, func(text string) (string, error) { + tokens := map[string]string{ + "CreateAssistantFileBody": "// CreateAssistantFileBody - The request details to use when creating an assistant file.", + "CreateMessageBody": "// CreateMessageBody - The request details to use when creating a message.", + "SubmitToolOutputsToRunBody": "// SubmitToolOutputsToRunBody - The request details to use when submitting tool outputs.", + "UpdateMessageBody": "// UpdateMessageBody - The request details to use when updating a message.", + "UpdateRunBody": "// UpdateRunBody - The request details to use when updating a run.", + "UpdateThreadBody": "// UpdateThreadBody - The request details to use when creating a thread.", + } + + // TODO: need to track down why these types don't have comments. + for goType, comment := range tokens { + origStructLine := fmt.Sprintf("type %s struct {", goType) + text = strings.Replace(text, origStructLine, comment+"\n"+origStructLine, 1) + } + + return text, nil + }, nil) +} diff --git a/sdk/ai/azopenaiassistants/internal/transform/transform_test.go b/sdk/ai/azopenaiassistants/internal/transform/transform_test.go new file mode 100644 index 000000000000..05d65cf21013 --- /dev/null +++ b/sdk/ai/azopenaiassistants/internal/transform/transform_test.go @@ -0,0 +1,108 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package main + +import ( + "os" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func loadFile(t *testing.T, path string) string { + data, err := os.ReadFile(path) + require.NoError(t, err) + + str := string(data) + + return strings.ReplaceAll(str, "\r\n", "\n") +} + +func TestFunction(t *testing.T) { + text := loadFile(t, "testdata/update_func.txt") + + newText, err := updateFunction(text, "Client", "uploadFileCreateRequest", func(text string) (string, error) { + return "MIDDLE", nil + }, &updateFunctionOptions{ + IgnoreComment: true, + }) + require.NoError(t, err) + require.Equal(t, "BEGIN\n// uploadFileCreateRequest creates the UploadFile request.\n// another line of documentation.\nMIDDLE\nEND\n", newText) + + newText, err = updateFunction(text, "Client", "uploadFileCreateRequest", func(text string) (string, error) { + return "MIDDLE", nil + }, &updateFunctionOptions{ + IgnoreComment: false, + }) + require.NoError(t, err) + require.Equal(t, "BEGIN\nMIDDLE\nEND\n", newText) +} + +func TestFunctionRemove(t *testing.T) { + text := loadFile(t, "testdata/remove_func.txt") + + newText, err := removeFunctions(text, "Client", "uploadFileCreateRequest") + require.NoError(t, err) + + require.Equal(t, "SOME TEXT BEFORE\n\n"+ + "// uploadFileHandleResponse handles the UploadFile response.\n"+ + "func (client *Client) uploadFileHandleResponse() error {\n"+ + " // another little function\n"+ + "}\n", newText) +} + +func TestSnipModel(t *testing.T) { + modelsText := loadFile(t, "testdata/remove_type_models.txt") + modelsSerdeText := loadFile(t, "testdata/remove_type_models_serde.txt") + + fileCache := &FileCache{ + files: map[string]string{ + "models.go": modelsText, + "models_serde.go": modelsSerdeText, + "responses.go": "ignored", + "options.go": "ignored", + }, + } + + err := removeTypes(fileCache, []string{"Paths1Filz8PFilesPostRequestbodyContentMultipartFormDataSchema"}, &removeTypesOptions{ + IgnoreComment: true, + }) + require.NoError(t, err) + + require.Equal(t, map[string]string{ + "models.go": "//Before that function\n\n\n//After that function\n", + "models_serde.go": "import (\n\t\"encoding/json\"\n\t\"fmt\"\n)\n\n//Before that model\n\n\n\n\n//After that model\n", + "responses.go": "ignored", + "options.go": "ignored", + }, fileCache.files) +} + +func TestSnipResponseType(t *testing.T) { + fileCache := &FileCache{ + files: map[string]string{ + "models.go": "ignored", + "models_serde.go": "ignored", + "responses.go": "hello\n// GetFileContentResponse contains the response from method Client.GetFileContent.\n" + + "type GetFileContentResponse struct {\n" + + " Value []byte\n" + + "}\n" + + " world", + "options.go": "ignored", + }, + } + + err := removeTypes(fileCache, []string{"GetFileContentResponse"}, nil) + require.NoError(t, err) + + require.Equal(t, map[string]string{ + "models.go": "ignored", + "models_serde.go": "ignored", + "responses.go": "hello\n\n world", + "options.go": "ignored", + }, fileCache.files) +} diff --git a/sdk/ai/azopenaiassistants/main_test.go b/sdk/ai/azopenaiassistants/main_test.go new file mode 100644 index 000000000000..67d05b4cee3b --- /dev/null +++ b/sdk/ai/azopenaiassistants/main_test.go @@ -0,0 +1,67 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants_test + +import ( + "fmt" + "log" + "os" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/internal/recording" + "github.com/joho/godotenv" +) + +type testVars struct { + OpenAIKey string + OpenAIEndpoint string + + AOAIKey string + AOAIEndpoint string +} + +var tv testVars + +const RecordingDirectory = "sdk/ai/azopenaiassistants/testdata" + +func TestMain(m *testing.M) { + err := godotenv.Load(".env") + + if err != nil { + log.Printf(".env file couldn't load: %s", err) + } + + tv.OpenAIKey = recording.GetEnvVariable("OPENAI_API_KEY", "key") + tv.OpenAIEndpoint = recording.GetEnvVariable("OPENAI_ENDPOINT", "https://openai.azure.com") + + tv.AOAIKey = recording.GetEnvVariable("AOAI_ASSISTANTS_KEY", "key") + tv.AOAIEndpoint = recording.GetEnvVariable("AOAI_ASSISTANTS_ENDPOINT", "https://openai.azure.com") + + os.Exit(run(m)) +} + +func run(m *testing.M) int { + if recording.GetRecordMode() == recording.PlaybackMode || recording.GetRecordMode() == recording.RecordingMode { + proxy, err := recording.StartTestProxy(RecordingDirectory, nil) + if err != nil { + panic(err) + } + + defer func() { + err := recording.StopTestProxy(proxy) + if err != nil { + panic(err) + } + }() + } else { + if err := godotenv.Load(); err != nil { + fmt.Printf("Failed to load .env file: %s\n", err) + } + } + + return m.Run() +} diff --git a/sdk/ai/azopenaiassistants/models.go b/sdk/ai/azopenaiassistants/models.go new file mode 100644 index 000000000000..293449548ea6 --- /dev/null +++ b/sdk/ai/azopenaiassistants/models.go @@ -0,0 +1,1157 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +import ( + "time" +) + +// Assistant - Represents an assistant that can call the model and use tools. +type Assistant struct { + // REQUIRED; The Unix timestamp, in seconds, representing when this object was created. + CreatedAt *time.Time + + // REQUIRED; The description of the assistant. + Description *string + + // REQUIRED; A list of attached file IDs, ordered by creation date in ascending order. + FileIDs []string + + // REQUIRED; The identifier, which can be referenced in API endpoints. + ID *string + + // REQUIRED; The system instructions for the assistant to use. + Instructions *string + + // REQUIRED; A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information + // about that object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // REQUIRED; The ID of the model to use. + DeploymentName *string + + // REQUIRED; The name of the assistant. + Name *string + + // REQUIRED; The object type, which is always assistant. + Object *string + + // REQUIRED; The collection of tools enabled for the assistant. + Tools []ToolDefinitionClassification +} + +// AssistantCreationBody - The request details to use when creating a new assistant. +type AssistantCreationBody struct { + // REQUIRED; The ID of the model to use. + DeploymentName *string + + // The description of the new assistant. + Description *string + + // A list of previously uploaded file IDs to attach to the assistant. + FileIDs []string + + // The system instructions for the new assistant to use. + Instructions *string + + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // The name of the new assistant. + Name *string + + // The collection of tools to enable for the new assistant. + Tools []ToolDefinitionClassification +} + +// AssistantDeletionStatus - The status of an assistant deletion operation. +type AssistantDeletionStatus struct { + // REQUIRED; A value indicating whether deletion was successful. + Deleted *bool + + // REQUIRED; The ID of the resource specified for deletion. + ID *string + + // REQUIRED; The object type, which is always 'assistant.deleted'. + Object *string +} + +// AssistantFile - Information about a file attached to an assistant, as used by tools that can read files. +type AssistantFile struct { + // REQUIRED; The assistant ID that the file is attached to. + AssistantID *string + + // REQUIRED; The Unix timestamp, in seconds, representing when this object was created. + CreatedAt *time.Time + + // REQUIRED; The identifier, which can be referenced in API endpoints. + ID *string + + // REQUIRED; The object type, which is always 'assistant.file'. + Object *string +} + +// AssistantFileDeletionStatus - The status of an assistant file deletion operation. +type AssistantFileDeletionStatus struct { + // REQUIRED; A value indicating whether deletion was successful. + Deleted *bool + + // REQUIRED; The ID of the resource specified for deletion. + ID *string + + // REQUIRED; The object type, which is always 'assistant.file.deleted'. + Object *string +} + +// AssistantThread - Information about a single thread associated with an assistant. +type AssistantThread struct { + // REQUIRED; The Unix timestamp, in seconds, representing when this object was created. + CreatedAt *time.Time + + // REQUIRED; The identifier, which can be referenced in API endpoints. + ID *string + + // REQUIRED; A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information + // about that object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // REQUIRED; The object type, which is always 'thread'. + Object *string +} + +// AssistantThreadCreationOptions - The details used to create a new assistant thread. +type AssistantThreadCreationOptions struct { + // The initial messages to associate with the new thread. + Messages []ThreadInitializationMessage + + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string +} + +// CodeInterpreterToolDefinition - The input definition information for a code interpreter tool as used to configure an assistant. +type CodeInterpreterToolDefinition struct { + // REQUIRED; The object type. + Type *string +} + +// GetToolDefinition implements the ToolDefinitionClassification interface for type CodeInterpreterToolDefinition. +func (c *CodeInterpreterToolDefinition) GetToolDefinition() *ToolDefinition { + return &ToolDefinition{ + Type: c.Type, + } +} + +// CreateAndRunThreadOptions - The details used when creating and immediately running a new assistant thread. +type CreateAndRunThreadOptions struct { + // REQUIRED; The ID of the assistant for which the thread should be created. + AssistantID *string + + // The overridden system instructions the assistant should use to run the thread. + Instructions *string + + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // The overridden model that the assistant should use to run the thread. + DeploymentName *string + + // The details used to create the new thread. + Thread *AssistantThreadCreationOptions + + // The overridden list of enabled tools the assistant should use to run the thread. + Tools []ToolDefinitionClassification +} + +// CreateRunBody - The details used when creating a new run of an assistant thread. +type CreateRunBody struct { + // REQUIRED; The ID of the assistant that should run the thread. + AssistantID *string + + // Additional instructions to append at the end of the instructions for the run. This is useful for modifying the behavior + // on a per-run basis without overriding other instructions. + AdditionalInstructions *string + + // The overridden system instructions that the assistant should use to run the thread. + Instructions *string + + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // The overridden model name that the assistant should use to run the thread. + DeploymentName *string + + // The overridden list of enabled tools that the assistant should use to run the thread. + Tools []ToolDefinitionClassification +} + +// FileDeletionStatus - A status response from a file deletion operation. +type FileDeletionStatus struct { + // REQUIRED; A value indicating whether deletion was successful. + Deleted *bool + + // REQUIRED; The ID of the resource specified for deletion. + ID *string + + // REQUIRED; The object type, which is always 'file'. + Object *string +} + +// FileListResponse - The response data from a file list operation. +type FileListResponse struct { + // REQUIRED; The files returned for the request. + Data []OpenAIFile + + // REQUIRED; The object type, which is always 'list'. + Object *string +} + +// FunctionDefinition - The input definition information for a function. +type FunctionDefinition struct { + // REQUIRED; The name of the function to be called. + Name *string + + // REQUIRED; The parameters the functions accepts, described as a JSON Schema object. + Parameters any + + // A description of what the function does, used by the model to choose when and how to call the function. + Description *string +} + +// FunctionToolDefinition - The input definition information for a function tool as used to configure an assistant. +type FunctionToolDefinition struct { + // REQUIRED; The definition of the concrete function that the function tool should call. + Function *FunctionDefinition + + // REQUIRED; The object type. + Type *string +} + +// GetToolDefinition implements the ToolDefinitionClassification interface for type FunctionToolDefinition. +func (f *FunctionToolDefinition) GetToolDefinition() *ToolDefinition { + return &ToolDefinition{ + Type: f.Type, + } +} + +// MessageContent - An abstract representation of a single item of thread message content. +type MessageContent struct { + // REQUIRED; The object type. + Type *string +} + +// GetMessageContent implements the MessageContentClassification interface for type MessageContent. +func (m *MessageContent) GetMessageContent() *MessageContent { return m } + +// MessageFile - Information about a file attached to an assistant thread message. +type MessageFile struct { + // REQUIRED; The Unix timestamp, in seconds, representing when this object was created. + CreatedAt *time.Time + + // REQUIRED; The identifier, which can be referenced in API endpoints. + ID *string + + // REQUIRED; The ID of the message that this file is attached to. + MessageID *string + + // REQUIRED; The object type, which is always 'thread.message.file'. + Object *string +} + +// MessageImageFileContent - A representation of image file content in a thread message. +type MessageImageFileContent struct { + // REQUIRED; The image file for this thread message content item. + ImageFile *MessageImageFileDetails + + // REQUIRED; The object type. + Type *string +} + +// GetMessageContent implements the MessageContentClassification interface for type MessageImageFileContent. +func (m *MessageImageFileContent) GetMessageContent() *MessageContent { + return &MessageContent{ + Type: m.Type, + } +} + +// MessageImageFileDetails - An image reference, as represented in thread message content. +type MessageImageFileDetails struct { + // REQUIRED; The ID for the file associated with this image. + FileID *string +} + +// MessageTextAnnotation - An abstract representation of an annotation to text thread message content. +type MessageTextAnnotation struct { + // REQUIRED; The last text index associated with this text annotation. + EndIndex *int32 + + // REQUIRED; The first text index associated with this text annotation. + StartIndex *int32 + + // REQUIRED; The textual content associated with this text annotation item. + Text *string + + // REQUIRED; The object type. + Type *string +} + +// GetMessageTextAnnotation implements the MessageTextAnnotationClassification interface for type MessageTextAnnotation. +func (m *MessageTextAnnotation) GetMessageTextAnnotation() *MessageTextAnnotation { return m } + +// MessageTextContent - A representation of a textual item of thread message content. +type MessageTextContent struct { + // REQUIRED; The text and associated annotations for this thread message content item. + Text *MessageTextDetails + + // REQUIRED; The object type. + Type *string +} + +// GetMessageContent implements the MessageContentClassification interface for type MessageTextContent. +func (m *MessageTextContent) GetMessageContent() *MessageContent { + return &MessageContent{ + Type: m.Type, + } +} + +// MessageTextDetails - The text and associated annotations for a single item of assistant thread message content. +type MessageTextDetails struct { + // REQUIRED; A list of annotations associated with this text. + Annotations []MessageTextAnnotationClassification + + // REQUIRED; The text data. + Value *string +} + +// MessageTextFileCitationAnnotation - A citation within the message that points to a specific quote from a specific File +// associated with the assistant or the message. Generated when the assistant uses the 'retrieval' tool to search files. +type MessageTextFileCitationAnnotation struct { + // REQUIRED; The last text index associated with this text annotation. + EndIndex *int32 + + // REQUIRED; A citation within the message that points to a specific quote from a specific file. Generated when the assistant + // uses the "retrieval" tool to search files. + FileCitation *MessageTextFileCitationDetails + + // REQUIRED; The first text index associated with this text annotation. + StartIndex *int32 + + // REQUIRED; The textual content associated with this text annotation item. + Text *string + + // REQUIRED; The object type. + Type *string +} + +// GetMessageTextAnnotation implements the MessageTextAnnotationClassification interface for type MessageTextFileCitationAnnotation. +func (m *MessageTextFileCitationAnnotation) GetMessageTextAnnotation() *MessageTextAnnotation { + return &MessageTextAnnotation{ + EndIndex: m.EndIndex, + StartIndex: m.StartIndex, + Text: m.Text, + Type: m.Type, + } +} + +// MessageTextFileCitationDetails - A representation of a file-based text citation, as used in a file-based annotation of +// text thread message content. +type MessageTextFileCitationDetails struct { + // REQUIRED; The ID of the file associated with this citation. + FileID *string + + // REQUIRED; The specific quote cited in the associated file. + Quote *string +} + +// MessageTextFilePathAnnotation - A citation within the message that points to a file located at a specific path. +type MessageTextFilePathAnnotation struct { + // REQUIRED; The last text index associated with this text annotation. + EndIndex *int32 + + // REQUIRED; A URL for the file that's generated when the assistant used the code_interpreter tool to generate a file. + FilePath *MessageTextFilePathDetails + + // REQUIRED; The first text index associated with this text annotation. + StartIndex *int32 + + // REQUIRED; The textual content associated with this text annotation item. + Text *string + + // REQUIRED; The object type. + Type *string +} + +// GetMessageTextAnnotation implements the MessageTextAnnotationClassification interface for type MessageTextFilePathAnnotation. +func (m *MessageTextFilePathAnnotation) GetMessageTextAnnotation() *MessageTextAnnotation { + return &MessageTextAnnotation{ + EndIndex: m.EndIndex, + StartIndex: m.StartIndex, + Text: m.Text, + Type: m.Type, + } +} + +// MessageTextFilePathDetails - An encapsulation of an image file ID, as used by message image content. +type MessageTextFilePathDetails struct { + // REQUIRED; The ID of the specific file that the citation is from. + FileID *string +} + +// OpenAIFile - Represents an assistant that can call the model and use tools. +type OpenAIFile struct { + // REQUIRED; The size of the file, in bytes. + Bytes *int32 + + // REQUIRED; The Unix timestamp, in seconds, representing when this object was created. + CreatedAt *time.Time + + // REQUIRED; The name of the file. + Filename *string + + // REQUIRED; The identifier, which can be referenced in API endpoints. + ID *string + + // REQUIRED; The object type, which is always 'file'. + Object *string + + // REQUIRED; The intended purpose of a file. + Purpose *FilePurpose +} + +// UpdateMessageBody - The request details to use when updating a message. +type UpdateMessageBody struct { + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string +} + +// SubmitToolOutputsToRunBody - The request details to use when submitting tool outputs. +type SubmitToolOutputsToRunBody struct { + // REQUIRED; The list of tool outputs requested by tool calls from the specified run. + ToolOutputs []ToolOutput +} + +// MessageFilesPage - The response data for a +// requested list of items. +type MessageFilesPage struct { + // REQUIRED; The requested list of items. + Data []MessageFile + + // REQUIRED; The first ID represented in this list. + FirstID *string + + // REQUIRED; A value indicating whether there are additional values available not captured in this list. + HasMore *bool + + // REQUIRED; The last ID represented in this list. + LastID *string + + // REQUIRED; The object type, which is always list. + Object *string +} + +// AssistantsPage - The response data for a requested list of items. +type AssistantsPage struct { + // REQUIRED; The requested list of items. + Data []Assistant + + // REQUIRED; The first ID represented in this list. + FirstID *string + + // REQUIRED; A value indicating whether there are additional values available not captured in this list. + HasMore *bool + + // REQUIRED; The last ID represented in this list. + LastID *string + + // REQUIRED; The object type, which is always list. + Object *string +} + +// CreateAssistantFileBody - The request details to use when creating an assistant file. +type CreateAssistantFileBody struct { + // REQUIRED; The ID of the previously uploaded file to attach. + FileID *string +} + +// MessagesPage - The response data for a requested list +// of items. +type MessagesPage struct { + // REQUIRED; The requested list of items. + Data []ThreadMessage + + // REQUIRED; The first ID represented in this list. + FirstID *string + + // REQUIRED; A value indicating whether there are additional values available not captured in this list. + HasMore *bool + + // REQUIRED; The last ID represented in this list. + LastID *string + + // REQUIRED; The object type, which is always list. + Object *string +} + +// UpdateRunBody - The request details to use when updating a run. +type UpdateRunBody struct { + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string +} + +// UpdateThreadBody - The request details to use when creating a thread. +type UpdateThreadBody struct { + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string +} + +// ThreadRunsPage - The response data for a requested list of items. +type ThreadRunsPage struct { + // REQUIRED; The requested list of items. + Data []ThreadRun + + // REQUIRED; The first ID represented in this list. + FirstID *string + + // REQUIRED; A value indicating whether there are additional values available not captured in this list. + HasMore *bool + + // REQUIRED; The last ID represented in this list. + LastID *string + + // REQUIRED; The object type, which is always list. + Object *string +} + +// RunStepsPage - The response data for a requested +// list of items. +type RunStepsPage struct { + // REQUIRED; The requested list of items. + Data []RunStep + + // REQUIRED; The first ID represented in this list. + FirstID *string + + // REQUIRED; A value indicating whether there are additional values available not captured in this list. + HasMore *bool + + // REQUIRED; The last ID represented in this list. + LastID *string + + // REQUIRED; The object type, which is always list. + Object *string +} + +// CreateMessageBody - The request details to use when creating a message. +type CreateMessageBody struct { + // REQUIRED; The textual content for the new message. + Content *string + + // REQUIRED; The role to associate with the new message. + Role *MessageRole + + // A list of up to 10 file IDs to associate with the message, as used by tools like 'code_interpreter' or 'retrieval' that + // can read files. + FileIDs []string + + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string +} + +// AssistantFilesPage - The response data for a requested list +// of items. +type AssistantFilesPage struct { + // REQUIRED; The requested list of items. + Data []AssistantFile + + // REQUIRED; The first ID represented in this list. + FirstID *string + + // REQUIRED; A value indicating whether there are additional values available not captured in this list. + HasMore *bool + + // REQUIRED; The last ID represented in this list. + LastID *string + + // REQUIRED; The object type, which is always list. + Object *string +} + +// RequiredAction - An abstract representation of a required action for an assistant thread run to continue. +type RequiredAction struct { + // REQUIRED; The object type. + Type *string +} + +// GetRequiredAction implements the RequiredActionClassification interface for type RequiredAction. +func (r *RequiredAction) GetRequiredAction() *RequiredAction { return r } + +// RequiredFunctionToolCall - A representation of a requested call to a function tool, needed by the model to continue evaluation +// of a run. +type RequiredFunctionToolCall struct { + // REQUIRED; Detailed information about the function to be executed by the tool that includes name and arguments. + Function *RequiredFunctionToolCallDetails + + // REQUIRED; The ID of the tool call. This ID must be referenced when submitting tool outputs. + ID *string + + // REQUIRED; The object type for the required tool call. + Type *string +} + +// GetRequiredToolCall implements the RequiredToolCallClassification interface for type RequiredFunctionToolCall. +func (r *RequiredFunctionToolCall) GetRequiredToolCall() *RequiredToolCall { + return &RequiredToolCall{ + ID: r.ID, + Type: r.Type, + } +} + +// RequiredFunctionToolCallDetails - The detailed information for a function invocation, as provided by a required action +// invoking a function tool, that includes the name of and arguments to the function. +type RequiredFunctionToolCallDetails struct { + // REQUIRED; The arguments to use when invoking the named function, as provided by the model. Arguments are presented as a + // JSON document that should be validated and parsed for evaluation. + Arguments *string + + // REQUIRED; The name of the function. + Name *string +} + +// RequiredToolCall - An abstract representation a a tool invocation needed by the model to continue a run. +type RequiredToolCall struct { + // REQUIRED; The ID of the tool call. This ID must be referenced when submitting tool outputs. + ID *string + + // REQUIRED; The object type for the required tool call. + Type *string +} + +// GetRequiredToolCall implements the RequiredToolCallClassification interface for type RequiredToolCall. +func (r *RequiredToolCall) GetRequiredToolCall() *RequiredToolCall { return r } + +// RetrievalToolDefinition - The input definition information for a retrieval tool as used to configure an assistant. +type RetrievalToolDefinition struct { + // REQUIRED; The object type. + Type *string +} + +// GetToolDefinition implements the ToolDefinitionClassification interface for type RetrievalToolDefinition. +func (r *RetrievalToolDefinition) GetToolDefinition() *ToolDefinition { + return &ToolDefinition{ + Type: r.Type, + } +} + +// RunError - The details of an error as encountered by an assistant thread run. +type RunError struct { + // REQUIRED; The status for the error. + Code *string + + // REQUIRED; The human-readable text associated with the error. + Message *string +} + +// RunStep - Detailed information about a single step of an assistant thread run. +type RunStep struct { + // REQUIRED; The ID of the assistant associated with the run step. + AssistantID *string + + // REQUIRED; The Unix timestamp, in seconds, representing when this was cancelled. + CancelledAt *time.Time + + // REQUIRED; The Unix timestamp, in seconds, representing when this completed. + CompletedAt *time.Time + + // REQUIRED; The Unix timestamp, in seconds, representing when this object was created. + CreatedAt *time.Time + + // REQUIRED; The Unix timestamp, in seconds, representing when this item expired. + ExpiredAt *time.Time + + // REQUIRED; The Unix timestamp, in seconds, representing when this failed. + FailedAt *time.Time + + // REQUIRED; The identifier, which can be referenced in API endpoints. + ID *string + + // REQUIRED; If applicable, information about the last error encountered by this run step. + LastError *RunStepLastError + + // REQUIRED; A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information + // about that object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // REQUIRED; The object type, which is always 'thread.run.step'. + Object *string + + // REQUIRED; The ID of the run that this run step is a part of. + RunID *string + + // REQUIRED; The status of this run step. + Status *RunStepStatus + + // REQUIRED; The details for this run step. + StepDetails RunStepDetailsClassification + + // REQUIRED; The ID of the thread that was run. + ThreadID *string + + // REQUIRED; The type of run step, which can be either messagecreation or toolcalls. + Type *RunStepType +} + +// RunStepCodeInterpreterImageOutput - A representation of an image output emitted by a code interpreter tool in response +// to a tool call by the model. +type RunStepCodeInterpreterImageOutput struct { + // REQUIRED; Referential information for the image associated with this output. + Image *RunStepCodeInterpreterImageReference + + // REQUIRED; The object type. + Type *string +} + +// GetRunStepCodeInterpreterToolCallOutput implements the RunStepCodeInterpreterToolCallOutputClassification interface for +// type RunStepCodeInterpreterImageOutput. +func (r *RunStepCodeInterpreterImageOutput) GetRunStepCodeInterpreterToolCallOutput() *RunStepCodeInterpreterToolCallOutput { + return &RunStepCodeInterpreterToolCallOutput{ + Type: r.Type, + } +} + +// RunStepCodeInterpreterImageReference - An image reference emitted by a code interpreter tool in response to a tool call +// by the model. +type RunStepCodeInterpreterImageReference struct { + // REQUIRED; The ID of the file associated with this image. + FileID *string +} + +// RunStepCodeInterpreterLogOutput - A representation of a log output emitted by a code interpreter tool in response to a +// tool call by the model. +type RunStepCodeInterpreterLogOutput struct { + // REQUIRED; The serialized log output emitted by the code interpreter. + Logs *string + + // REQUIRED; The object type. + Type *string +} + +// GetRunStepCodeInterpreterToolCallOutput implements the RunStepCodeInterpreterToolCallOutputClassification interface for +// type RunStepCodeInterpreterLogOutput. +func (r *RunStepCodeInterpreterLogOutput) GetRunStepCodeInterpreterToolCallOutput() *RunStepCodeInterpreterToolCallOutput { + return &RunStepCodeInterpreterToolCallOutput{ + Type: r.Type, + } +} + +// RunStepCodeInterpreterToolCall - A record of a call to a code interpreter tool, issued by the model in evaluation of a +// defined tool, that represents inputs and outputs consumed and emitted by the code interpreter. +type RunStepCodeInterpreterToolCall struct { + // REQUIRED; The details of the tool call to the code interpreter tool. + CodeInterpreter *RunStepCodeInterpreterToolCallDetails + + // REQUIRED; The ID of the tool call. This ID must be referenced when you submit tool outputs. + ID *string + + // REQUIRED; The object type. + Type *string +} + +// GetRunStepToolCall implements the RunStepToolCallClassification interface for type RunStepCodeInterpreterToolCall. +func (r *RunStepCodeInterpreterToolCall) GetRunStepToolCall() *RunStepToolCall { + return &RunStepToolCall{ + ID: r.ID, + Type: r.Type, + } +} + +// RunStepCodeInterpreterToolCallDetails - The detailed information about a code interpreter invocation by the model. +type RunStepCodeInterpreterToolCallDetails struct { + // REQUIRED; The input provided by the model to the code interpreter tool. + Input *string + + // REQUIRED; The outputs produced by the code interpreter tool back to the model in response to the tool call. + Outputs []RunStepCodeInterpreterToolCallOutputClassification +} + +// RunStepCodeInterpreterToolCallOutput - An abstract representation of an emitted output from a code interpreter tool. +type RunStepCodeInterpreterToolCallOutput struct { + // REQUIRED; The object type. + Type *string +} + +// GetRunStepCodeInterpreterToolCallOutput implements the RunStepCodeInterpreterToolCallOutputClassification interface for +// type RunStepCodeInterpreterToolCallOutput. +func (r *RunStepCodeInterpreterToolCallOutput) GetRunStepCodeInterpreterToolCallOutput() *RunStepCodeInterpreterToolCallOutput { + return r +} + +// RunStepDetails - An abstract representation of the details for a run step. +type RunStepDetails struct { + // REQUIRED; The object type. + Type *RunStepType +} + +// GetRunStepDetails implements the RunStepDetailsClassification interface for type RunStepDetails. +func (r *RunStepDetails) GetRunStepDetails() *RunStepDetails { return r } + +// RunStepError - The error information associated with a failed run step. +type RunStepError struct { + // REQUIRED; The error code for this error. + Code *RunStepErrorCode + + // REQUIRED; The human-readable text associated with this error. + Message *string +} + +// RunStepFunctionToolCall - A record of a call to a function tool, issued by the model in evaluation of a defined tool, that +// represents the inputs and output consumed and emitted by the specified function. +type RunStepFunctionToolCall struct { + // REQUIRED; The detailed information about the function called by the model. + Function *RunStepFunctionToolCallDetails + + // REQUIRED; The ID of the tool call. This ID must be referenced when you submit tool outputs. + ID *string + + // REQUIRED; The object type. + Type *string +} + +// GetRunStepToolCall implements the RunStepToolCallClassification interface for type RunStepFunctionToolCall. +func (r *RunStepFunctionToolCall) GetRunStepToolCall() *RunStepToolCall { + return &RunStepToolCall{ + ID: r.ID, + Type: r.Type, + } +} + +// RunStepFunctionToolCallDetails - The detailed information about the function called by the model. +type RunStepFunctionToolCallDetails struct { + // REQUIRED; The arguments that the model requires are provided to the named function. + Arguments *string + + // REQUIRED; The name of the function. + Name *string + + // REQUIRED; The output of the function, only populated for function calls that have already have had their outputs submitted. + Output *string +} + +// RunStepLastError - If applicable, information about the last error encountered by this run step. +type RunStepLastError struct { + // REQUIRED; The error code for this error. + Code *RunStepErrorCode + + // REQUIRED; The human-readable text associated with this error. + Message *string +} + +// RunStepMessageCreationDetails - The detailed information associated with a message creation run step. +type RunStepMessageCreationDetails struct { + // REQUIRED; Information about the message creation associated with this run step. + MessageCreation *RunStepMessageCreationReference + + // REQUIRED; The object type. + Type *RunStepType +} + +// GetRunStepDetails implements the RunStepDetailsClassification interface for type RunStepMessageCreationDetails. +func (r *RunStepMessageCreationDetails) GetRunStepDetails() *RunStepDetails { + return &RunStepDetails{ + Type: r.Type, + } +} + +// RunStepMessageCreationReference - The details of a message created as a part of a run step. +type RunStepMessageCreationReference struct { + // REQUIRED; The ID of the message created by this run step. + MessageID *string +} + +// RunStepRetrievalToolCall - A record of a call to a retrieval tool, issued by the model in evaluation of a defined tool, +// that represents executed retrieval actions. +type RunStepRetrievalToolCall struct { + // REQUIRED; The ID of the tool call. This ID must be referenced when you submit tool outputs. + ID *string + + // REQUIRED; The key/value pairs produced by the retrieval tool. + Retrieval map[string]*string + + // REQUIRED; The object type. + Type *string +} + +// GetRunStepToolCall implements the RunStepToolCallClassification interface for type RunStepRetrievalToolCall. +func (r *RunStepRetrievalToolCall) GetRunStepToolCall() *RunStepToolCall { + return &RunStepToolCall{ + ID: r.ID, + Type: r.Type, + } +} + +// RunStepToolCall - An abstract representation of a detailed tool call as recorded within a run step for an existing run. +type RunStepToolCall struct { + // REQUIRED; The ID of the tool call. This ID must be referenced when you submit tool outputs. + ID *string + + // REQUIRED; The object type. + Type *string +} + +// GetRunStepToolCall implements the RunStepToolCallClassification interface for type RunStepToolCall. +func (r *RunStepToolCall) GetRunStepToolCall() *RunStepToolCall { return r } + +// RunStepToolCallDetails - The detailed information associated with a run step calling tools. +type RunStepToolCallDetails struct { + // REQUIRED; A list of tool call details for this run step. + ToolCalls []RunStepToolCallClassification + + // REQUIRED; The object type. + Type *RunStepType +} + +// GetRunStepDetails implements the RunStepDetailsClassification interface for type RunStepToolCallDetails. +func (r *RunStepToolCallDetails) GetRunStepDetails() *RunStepDetails { + return &RunStepDetails{ + Type: r.Type, + } +} + +// SubmitToolOutputsAction - The details for required tool calls that must be submitted for an assistant thread run to continue. +type SubmitToolOutputsAction struct { + // REQUIRED; The details describing tools that should be called to submit tool outputs. + SubmitToolOutputs *SubmitToolOutputsDetails + + // REQUIRED; The object type. + Type *string +} + +// GetRequiredAction implements the RequiredActionClassification interface for type SubmitToolOutputsAction. +func (s *SubmitToolOutputsAction) GetRequiredAction() *RequiredAction { + return &RequiredAction{ + Type: s.Type, + } +} + +// SubmitToolOutputsDetails - The details describing tools that should be called to submit tool outputs. +type SubmitToolOutputsDetails struct { + // REQUIRED; The list of tool calls that must be resolved for the assistant thread run to continue. + ToolCalls []RequiredToolCallClassification +} + +// ThreadDeletionStatus - The status of a thread deletion operation. +type ThreadDeletionStatus struct { + // REQUIRED; A value indicating whether deletion was successful. + Deleted *bool + + // REQUIRED; The ID of the resource specified for deletion. + ID *string + + // REQUIRED; The object type, which is always 'thread.deleted'. + Object *string +} + +// ThreadInitializationMessage - A single message within an assistant thread, as provided during that thread's creation for +// its initial state. +type ThreadInitializationMessage struct { + // REQUIRED; The textual content of the initial message. Currently, robust input including images and annotated text may only + // be provided via a separate call to the create message API. + Content *string + + // REQUIRED; The role associated with the assistant thread message. Currently, only 'user' is supported when providing initial + // messages to a new thread. + Role *MessageRole + + // A list of file IDs that the assistant should use. Useful for tools like retrieval and code_interpreter that can access + // files. + FileIDs []string + + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string +} + +// ThreadMessage - A single, existing message within an assistant thread. +type ThreadMessage struct { + // REQUIRED; The list of content items associated with the assistant thread message. + Content []MessageContentClassification + + // REQUIRED; The Unix timestamp, in seconds, representing when this object was created. + CreatedAt *time.Time + + // REQUIRED; A list of file IDs that the assistant should use. Useful for tools like retrieval and code_interpreter that can + // access files. + FileIDs []string + + // REQUIRED; The identifier, which can be referenced in API endpoints. + ID *string + + // REQUIRED; A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information + // about that object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // REQUIRED; The object type, which is always 'thread.message'. + Object *string + + // REQUIRED; The role associated with the assistant thread message. + Role *MessageRole + + // REQUIRED; The ID of the thread that this message belongs to. + ThreadID *string + + // If applicable, the ID of the assistant that authored this message. + AssistantID *string + + // If applicable, the ID of the run associated with the authoring of this message. + RunID *string +} + +// ThreadRun - Data representing a single evaluation run of an assistant thread. +type ThreadRun struct { + // REQUIRED; The ID of the assistant associated with the thread this run was performed against. + AssistantID *string + + // REQUIRED; The Unix timestamp, in seconds, representing when this was cancelled. + CancelledAt *time.Time + + // REQUIRED; The Unix timestamp, in seconds, representing when this completed. + CompletedAt *time.Time + + // REQUIRED; The Unix timestamp, in seconds, representing when this object was created. + CreatedAt *time.Time + + // REQUIRED; The Unix timestamp, in seconds, representing when this item expires. + ExpiresAt *time.Time + + // REQUIRED; The Unix timestamp, in seconds, representing when this failed. + FailedAt *time.Time + + // REQUIRED; A list of attached file IDs, ordered by creation date in ascending order. + FileIDs []string + + // REQUIRED; The identifier, which can be referenced in API endpoints. + ID *string + + // REQUIRED; The overridden system instructions used for this assistant thread run. + Instructions *string + + // REQUIRED; The last error, if any, encountered by this assistant thread run. + LastError *ThreadRunLastError + + // REQUIRED; A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information + // about that object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // REQUIRED; The ID of the model to use. + DeploymentName *string + + // REQUIRED; The object type, which is always 'thread.run'. + Object *string + + // REQUIRED; The Unix timestamp, in seconds, representing when this item was started. + StartedAt *time.Time + + // REQUIRED; The status of the assistant thread run. + Status *RunStatus + + // REQUIRED; The ID of the thread associated with this run. + ThreadID *string + + // REQUIRED; The overridden enabled tools used for this assistant thread run. + Tools []ToolDefinitionClassification + + // The details of the action required for the assistant thread run to continue. + RequiredAction *ThreadRunRequiredAction +} + +// ThreadRunLastError - The last error, if any, encountered by this assistant thread run. +type ThreadRunLastError struct { + // REQUIRED; The status for the error. + Code *string + + // REQUIRED; The human-readable text associated with the error. + Message *string +} + +// ThreadRunRequiredAction - The details of the action required for the assistant thread run to continue. +type ThreadRunRequiredAction struct { + // REQUIRED; The object type. + Type *string +} + +// GetRequiredAction implements the RequiredActionClassification interface for type ThreadRunRequiredAction. +func (t *ThreadRunRequiredAction) GetRequiredAction() *RequiredAction { + return &RequiredAction{ + Type: t.Type, + } +} + +// ToolDefinition - An abstract representation of an input tool definition that an assistant can use. +type ToolDefinition struct { + // REQUIRED; The object type. + Type *string +} + +// GetToolDefinition implements the ToolDefinitionClassification interface for type ToolDefinition. +func (t *ToolDefinition) GetToolDefinition() *ToolDefinition { return t } + +// ToolOutput - The data provided during a tool outputs submission to resolve pending tool calls and allow the model to continue. +type ToolOutput struct { + // The output from the tool to be submitted. + Output *string + + // The ID of the tool call being resolved, as provided in the tool calls of a required action from a run. + ToolCallID *string +} + +// UpdateAssistantBody - The request details to use when modifying an existing assistant. +type UpdateAssistantBody struct { + // The modified description for the assistant to use. + Description *string + + // The modified list of previously uploaded fileIDs to attach to the assistant. + FileIDs []string + + // The modified system instructions for the new assistant to use. + Instructions *string + + // A set of up to 16 key/value pairs that can be attached to an object, used for storing additional information about that + // object in a structured format. Keys may be up to 64 characters in length and + // values may be up to 512 characters in length. + Metadata map[string]*string + + // The ID of the model to use. + DeploymentName *string + + // The modified name for the assistant to use. + Name *string + + // The modified collection of tools to enable for the assistant. + Tools []ToolDefinitionClassification +} diff --git a/sdk/ai/azopenaiassistants/models_serde.go b/sdk/ai/azopenaiassistants/models_serde.go new file mode 100644 index 000000000000..acd03185c33b --- /dev/null +++ b/sdk/ai/azopenaiassistants/models_serde.go @@ -0,0 +1,2659 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +import ( + "encoding/json" + "fmt" + "reflect" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +// MarshalJSON implements the json.Marshaller interface for type Assistant. +func (a Assistant) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populateTimeUnix(objectMap, "created_at", a.CreatedAt) + populate(objectMap, "description", a.Description) + populate(objectMap, "file_ids", a.FileIDs) + populate(objectMap, "id", a.ID) + populate(objectMap, "instructions", a.Instructions) + populate(objectMap, "metadata", a.Metadata) + populate(objectMap, "model", a.DeploymentName) + populate(objectMap, "name", a.Name) + objectMap["object"] = "assistant" + populate(objectMap, "tools", a.Tools) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type Assistant. +func (a *Assistant) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "created_at": + err = unpopulateTimeUnix(val, "CreatedAt", &a.CreatedAt) + delete(rawMsg, key) + case "description": + err = unpopulate(val, "Description", &a.Description) + delete(rawMsg, key) + case "file_ids": + err = unpopulate(val, "FileIDs", &a.FileIDs) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &a.ID) + delete(rawMsg, key) + case "instructions": + err = unpopulate(val, "Instructions", &a.Instructions) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &a.Metadata) + delete(rawMsg, key) + case "model": + err = unpopulate(val, "Model", &a.DeploymentName) + delete(rawMsg, key) + case "name": + err = unpopulate(val, "Name", &a.Name) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &a.Object) + delete(rawMsg, key) + case "tools": + a.Tools, err = unmarshalToolDefinitionClassificationArray(val) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AssistantCreationBody. +func (a AssistantCreationBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "description", a.Description) + populate(objectMap, "file_ids", a.FileIDs) + populate(objectMap, "instructions", a.Instructions) + populate(objectMap, "metadata", a.Metadata) + populate(objectMap, "model", a.DeploymentName) + populate(objectMap, "name", a.Name) + populate(objectMap, "tools", a.Tools) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AssistantCreationBody. +func (a *AssistantCreationBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "description": + err = unpopulate(val, "Description", &a.Description) + delete(rawMsg, key) + case "file_ids": + err = unpopulate(val, "FileIDs", &a.FileIDs) + delete(rawMsg, key) + case "instructions": + err = unpopulate(val, "Instructions", &a.Instructions) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &a.Metadata) + delete(rawMsg, key) + case "model": + err = unpopulate(val, "Model", &a.DeploymentName) + delete(rawMsg, key) + case "name": + err = unpopulate(val, "Name", &a.Name) + delete(rawMsg, key) + case "tools": + a.Tools, err = unmarshalToolDefinitionClassificationArray(val) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AssistantDeletionStatus. +func (a AssistantDeletionStatus) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "deleted", a.Deleted) + populate(objectMap, "id", a.ID) + objectMap["object"] = "assistant.deleted" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AssistantDeletionStatus. +func (a *AssistantDeletionStatus) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "deleted": + err = unpopulate(val, "Deleted", &a.Deleted) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &a.ID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &a.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AssistantFile. +func (a AssistantFile) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "assistant_id", a.AssistantID) + populateTimeUnix(objectMap, "created_at", a.CreatedAt) + populate(objectMap, "id", a.ID) + objectMap["object"] = "assistant.file" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AssistantFile. +func (a *AssistantFile) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "assistant_id": + err = unpopulate(val, "AssistantID", &a.AssistantID) + delete(rawMsg, key) + case "created_at": + err = unpopulateTimeUnix(val, "CreatedAt", &a.CreatedAt) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &a.ID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &a.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AssistantFileDeletionStatus. +func (a AssistantFileDeletionStatus) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "deleted", a.Deleted) + populate(objectMap, "id", a.ID) + objectMap["object"] = "assistant.file.deleted" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AssistantFileDeletionStatus. +func (a *AssistantFileDeletionStatus) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "deleted": + err = unpopulate(val, "Deleted", &a.Deleted) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &a.ID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &a.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AssistantThread. +func (a AssistantThread) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populateTimeUnix(objectMap, "created_at", a.CreatedAt) + populate(objectMap, "id", a.ID) + populate(objectMap, "metadata", a.Metadata) + objectMap["object"] = "thread" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AssistantThread. +func (a *AssistantThread) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "created_at": + err = unpopulateTimeUnix(val, "CreatedAt", &a.CreatedAt) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &a.ID) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &a.Metadata) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &a.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AssistantThreadCreationOptions. +func (a AssistantThreadCreationOptions) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "messages", a.Messages) + populate(objectMap, "metadata", a.Metadata) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AssistantThreadCreationOptions. +func (a *AssistantThreadCreationOptions) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "messages": + err = unpopulate(val, "Messages", &a.Messages) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &a.Metadata) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", a, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type CodeInterpreterToolDefinition. +func (c CodeInterpreterToolDefinition) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + objectMap["type"] = "code_interpreter" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type CodeInterpreterToolDefinition. +func (c *CodeInterpreterToolDefinition) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", c, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "type": + err = unpopulate(val, "Type", &c.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", c, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type CreateAndRunThreadOptions. +func (c CreateAndRunThreadOptions) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "assistant_id", c.AssistantID) + populate(objectMap, "instructions", c.Instructions) + populate(objectMap, "metadata", c.Metadata) + populate(objectMap, "model", c.DeploymentName) + populate(objectMap, "thread", c.Thread) + populate(objectMap, "tools", c.Tools) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type CreateAndRunThreadOptions. +func (c *CreateAndRunThreadOptions) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", c, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "assistant_id": + err = unpopulate(val, "AssistantID", &c.AssistantID) + delete(rawMsg, key) + case "instructions": + err = unpopulate(val, "Instructions", &c.Instructions) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &c.Metadata) + delete(rawMsg, key) + case "model": + err = unpopulate(val, "Model", &c.DeploymentName) + delete(rawMsg, key) + case "thread": + err = unpopulate(val, "Thread", &c.Thread) + delete(rawMsg, key) + case "tools": + c.Tools, err = unmarshalToolDefinitionClassificationArray(val) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", c, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type CreateRunBody. +func (c CreateRunBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "additional_instructions", c.AdditionalInstructions) + populate(objectMap, "assistant_id", c.AssistantID) + populate(objectMap, "instructions", c.Instructions) + populate(objectMap, "metadata", c.Metadata) + populate(objectMap, "model", c.DeploymentName) + populate(objectMap, "tools", c.Tools) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type CreateRunBody. +func (c *CreateRunBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", c, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "additional_instructions": + err = unpopulate(val, "AdditionalInstructions", &c.AdditionalInstructions) + delete(rawMsg, key) + case "assistant_id": + err = unpopulate(val, "AssistantID", &c.AssistantID) + delete(rawMsg, key) + case "instructions": + err = unpopulate(val, "Instructions", &c.Instructions) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &c.Metadata) + delete(rawMsg, key) + case "model": + err = unpopulate(val, "Model", &c.DeploymentName) + delete(rawMsg, key) + case "tools": + c.Tools, err = unmarshalToolDefinitionClassificationArray(val) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", c, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type FileDeletionStatus. +func (f FileDeletionStatus) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "deleted", f.Deleted) + populate(objectMap, "id", f.ID) + objectMap["object"] = "file" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type FileDeletionStatus. +func (f *FileDeletionStatus) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", f, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "deleted": + err = unpopulate(val, "Deleted", &f.Deleted) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &f.ID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &f.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", f, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type FileListResponse. +func (f FileListResponse) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "data", f.Data) + objectMap["object"] = "list" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type FileListResponse. +func (f *FileListResponse) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", f, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "data": + err = unpopulate(val, "Data", &f.Data) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &f.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", f, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type FunctionDefinition. +func (f FunctionDefinition) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "description", f.Description) + populate(objectMap, "name", f.Name) + populateAny(objectMap, "parameters", f.Parameters) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type FunctionDefinition. +func (f *FunctionDefinition) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", f, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "description": + err = unpopulate(val, "Description", &f.Description) + delete(rawMsg, key) + case "name": + err = unpopulate(val, "Name", &f.Name) + delete(rawMsg, key) + case "parameters": + err = unpopulate(val, "Parameters", &f.Parameters) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", f, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type FunctionToolDefinition. +func (f FunctionToolDefinition) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "function", f.Function) + objectMap["type"] = "function" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type FunctionToolDefinition. +func (f *FunctionToolDefinition) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", f, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "function": + err = unpopulate(val, "Function", &f.Function) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &f.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", f, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageContent. +func (m MessageContent) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + objectMap["type"] = m.Type + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageContent. +func (m *MessageContent) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "type": + err = unpopulate(val, "Type", &m.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageFile. +func (m MessageFile) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populateTimeUnix(objectMap, "created_at", m.CreatedAt) + populate(objectMap, "id", m.ID) + populate(objectMap, "message_id", m.MessageID) + objectMap["object"] = "thread.message.file" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageFile. +func (m *MessageFile) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "created_at": + err = unpopulateTimeUnix(val, "CreatedAt", &m.CreatedAt) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &m.ID) + delete(rawMsg, key) + case "message_id": + err = unpopulate(val, "MessageID", &m.MessageID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &m.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageImageFileContent. +func (m MessageImageFileContent) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "image_file", m.ImageFile) + objectMap["type"] = "image_file" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageImageFileContent. +func (m *MessageImageFileContent) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "image_file": + err = unpopulate(val, "ImageFile", &m.ImageFile) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &m.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageImageFileDetails. +func (m MessageImageFileDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "file_id", m.FileID) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageImageFileDetails. +func (m *MessageImageFileDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "file_id": + err = unpopulate(val, "FileID", &m.FileID) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageTextAnnotation. +func (m MessageTextAnnotation) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "end_index", m.EndIndex) + populate(objectMap, "start_index", m.StartIndex) + populate(objectMap, "text", m.Text) + objectMap["type"] = m.Type + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageTextAnnotation. +func (m *MessageTextAnnotation) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "end_index": + err = unpopulate(val, "EndIndex", &m.EndIndex) + delete(rawMsg, key) + case "start_index": + err = unpopulate(val, "StartIndex", &m.StartIndex) + delete(rawMsg, key) + case "text": + err = unpopulate(val, "Text", &m.Text) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &m.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageTextContent. +func (m MessageTextContent) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "text", m.Text) + objectMap["type"] = "text" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageTextContent. +func (m *MessageTextContent) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "text": + err = unpopulate(val, "Text", &m.Text) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &m.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageTextDetails. +func (m MessageTextDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "annotations", m.Annotations) + populate(objectMap, "value", m.Value) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageTextDetails. +func (m *MessageTextDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "annotations": + m.Annotations, err = unmarshalMessageTextAnnotationClassificationArray(val) + delete(rawMsg, key) + case "value": + err = unpopulate(val, "Value", &m.Value) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageTextFileCitationAnnotation. +func (m MessageTextFileCitationAnnotation) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "end_index", m.EndIndex) + populate(objectMap, "file_citation", m.FileCitation) + populate(objectMap, "start_index", m.StartIndex) + populate(objectMap, "text", m.Text) + objectMap["type"] = "file_citation" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageTextFileCitationAnnotation. +func (m *MessageTextFileCitationAnnotation) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "end_index": + err = unpopulate(val, "EndIndex", &m.EndIndex) + delete(rawMsg, key) + case "file_citation": + err = unpopulate(val, "FileCitation", &m.FileCitation) + delete(rawMsg, key) + case "start_index": + err = unpopulate(val, "StartIndex", &m.StartIndex) + delete(rawMsg, key) + case "text": + err = unpopulate(val, "Text", &m.Text) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &m.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageTextFileCitationDetails. +func (m MessageTextFileCitationDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "file_id", m.FileID) + populate(objectMap, "quote", m.Quote) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageTextFileCitationDetails. +func (m *MessageTextFileCitationDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "file_id": + err = unpopulate(val, "FileID", &m.FileID) + delete(rawMsg, key) + case "quote": + err = unpopulate(val, "Quote", &m.Quote) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageTextFilePathAnnotation. +func (m MessageTextFilePathAnnotation) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "end_index", m.EndIndex) + populate(objectMap, "file_path", m.FilePath) + populate(objectMap, "start_index", m.StartIndex) + populate(objectMap, "text", m.Text) + objectMap["type"] = "file_path" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageTextFilePathAnnotation. +func (m *MessageTextFilePathAnnotation) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "end_index": + err = unpopulate(val, "EndIndex", &m.EndIndex) + delete(rawMsg, key) + case "file_path": + err = unpopulate(val, "FilePath", &m.FilePath) + delete(rawMsg, key) + case "start_index": + err = unpopulate(val, "StartIndex", &m.StartIndex) + delete(rawMsg, key) + case "text": + err = unpopulate(val, "Text", &m.Text) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &m.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageTextFilePathDetails. +func (m MessageTextFilePathDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "file_id", m.FileID) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageTextFilePathDetails. +func (m *MessageTextFilePathDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "file_id": + err = unpopulate(val, "FileID", &m.FileID) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", m, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type OpenAIFile. +func (o OpenAIFile) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "bytes", o.Bytes) + populateTimeUnix(objectMap, "created_at", o.CreatedAt) + populate(objectMap, "filename", o.Filename) + populate(objectMap, "id", o.ID) + objectMap["object"] = "file" + populate(objectMap, "purpose", o.Purpose) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type OpenAIFile. +func (o *OpenAIFile) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", o, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "bytes": + err = unpopulate(val, "Bytes", &o.Bytes) + delete(rawMsg, key) + case "created_at": + err = unpopulateTimeUnix(val, "CreatedAt", &o.CreatedAt) + delete(rawMsg, key) + case "filename": + err = unpopulate(val, "Filename", &o.Filename) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &o.ID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &o.Object) + delete(rawMsg, key) + case "purpose": + err = unpopulate(val, "Purpose", &o.Purpose) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", o, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type UpdateMessageBody. +func (p UpdateMessageBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "metadata", p.Metadata) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type UpdateMessageBody. +func (p *UpdateMessageBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "metadata": + err = unpopulate(val, "Metadata", &p.Metadata) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type SubmitToolOutputsToRunBody. +func (p SubmitToolOutputsToRunBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "tool_outputs", p.ToolOutputs) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type SubmitToolOutputsToRunBody. +func (p *SubmitToolOutputsToRunBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "tool_outputs": + err = unpopulate(val, "ToolOutputs", &p.ToolOutputs) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessageFilesPage. +func (p MessageFilesPage) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "data", p.Data) + populate(objectMap, "first_id", p.FirstID) + populate(objectMap, "has_more", p.HasMore) + populate(objectMap, "last_id", p.LastID) + objectMap["object"] = "list" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessageFilesPage. +func (p *MessageFilesPage) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "data": + err = unpopulate(val, "Data", &p.Data) + delete(rawMsg, key) + case "first_id": + err = unpopulate(val, "FirstID", &p.FirstID) + delete(rawMsg, key) + case "has_more": + err = unpopulate(val, "HasMore", &p.HasMore) + delete(rawMsg, key) + case "last_id": + err = unpopulate(val, "LastID", &p.LastID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &p.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AssistantsPage. +func (p AssistantsPage) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "data", p.Data) + populate(objectMap, "first_id", p.FirstID) + populate(objectMap, "has_more", p.HasMore) + populate(objectMap, "last_id", p.LastID) + objectMap["object"] = "list" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AssistantsPage. +func (p *AssistantsPage) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "data": + err = unpopulate(val, "Data", &p.Data) + delete(rawMsg, key) + case "first_id": + err = unpopulate(val, "FirstID", &p.FirstID) + delete(rawMsg, key) + case "has_more": + err = unpopulate(val, "HasMore", &p.HasMore) + delete(rawMsg, key) + case "last_id": + err = unpopulate(val, "LastID", &p.LastID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &p.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type CreateAssistantFileBody. +func (p CreateAssistantFileBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "file_id", p.FileID) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type CreateAssistantFileBody. +func (p *CreateAssistantFileBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "file_id": + err = unpopulate(val, "FileID", &p.FileID) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type MessagesPage. +func (p MessagesPage) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "data", p.Data) + populate(objectMap, "first_id", p.FirstID) + populate(objectMap, "has_more", p.HasMore) + populate(objectMap, "last_id", p.LastID) + objectMap["object"] = "list" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type MessagesPage. +func (p *MessagesPage) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "data": + err = unpopulate(val, "Data", &p.Data) + delete(rawMsg, key) + case "first_id": + err = unpopulate(val, "FirstID", &p.FirstID) + delete(rawMsg, key) + case "has_more": + err = unpopulate(val, "HasMore", &p.HasMore) + delete(rawMsg, key) + case "last_id": + err = unpopulate(val, "LastID", &p.LastID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &p.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type UpdateRunBody. +func (p UpdateRunBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "metadata", p.Metadata) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type UpdateRunBody. +func (p *UpdateRunBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "metadata": + err = unpopulate(val, "Metadata", &p.Metadata) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type UpdateThreadBody. +func (p UpdateThreadBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "metadata", p.Metadata) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type UpdateThreadBody. +func (p *UpdateThreadBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "metadata": + err = unpopulate(val, "Metadata", &p.Metadata) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ThreadRunsPage. +func (p ThreadRunsPage) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "data", p.Data) + populate(objectMap, "first_id", p.FirstID) + populate(objectMap, "has_more", p.HasMore) + populate(objectMap, "last_id", p.LastID) + objectMap["object"] = "list" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ThreadRunsPage. +func (p *ThreadRunsPage) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "data": + err = unpopulate(val, "Data", &p.Data) + delete(rawMsg, key) + case "first_id": + err = unpopulate(val, "FirstID", &p.FirstID) + delete(rawMsg, key) + case "has_more": + err = unpopulate(val, "HasMore", &p.HasMore) + delete(rawMsg, key) + case "last_id": + err = unpopulate(val, "LastID", &p.LastID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &p.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepsPage. +func (p RunStepsPage) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "data", p.Data) + populate(objectMap, "first_id", p.FirstID) + populate(objectMap, "has_more", p.HasMore) + populate(objectMap, "last_id", p.LastID) + objectMap["object"] = "list" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepsPage. +func (p *RunStepsPage) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "data": + err = unpopulate(val, "Data", &p.Data) + delete(rawMsg, key) + case "first_id": + err = unpopulate(val, "FirstID", &p.FirstID) + delete(rawMsg, key) + case "has_more": + err = unpopulate(val, "HasMore", &p.HasMore) + delete(rawMsg, key) + case "last_id": + err = unpopulate(val, "LastID", &p.LastID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &p.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type CreateMessageBody. +func (p CreateMessageBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "content", p.Content) + populate(objectMap, "file_ids", p.FileIDs) + populate(objectMap, "metadata", p.Metadata) + populate(objectMap, "role", p.Role) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type CreateMessageBody. +func (p *CreateMessageBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "content": + err = unpopulate(val, "Content", &p.Content) + delete(rawMsg, key) + case "file_ids": + err = unpopulate(val, "FileIDs", &p.FileIDs) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &p.Metadata) + delete(rawMsg, key) + case "role": + err = unpopulate(val, "Role", &p.Role) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type AssistantFilesPage. +func (p AssistantFilesPage) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "data", p.Data) + populate(objectMap, "first_id", p.FirstID) + populate(objectMap, "has_more", p.HasMore) + populate(objectMap, "last_id", p.LastID) + objectMap["object"] = "list" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type AssistantFilesPage. +func (p *AssistantFilesPage) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "data": + err = unpopulate(val, "Data", &p.Data) + delete(rawMsg, key) + case "first_id": + err = unpopulate(val, "FirstID", &p.FirstID) + delete(rawMsg, key) + case "has_more": + err = unpopulate(val, "HasMore", &p.HasMore) + delete(rawMsg, key) + case "last_id": + err = unpopulate(val, "LastID", &p.LastID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &p.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", p, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RequiredAction. +func (r RequiredAction) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + objectMap["type"] = r.Type + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RequiredAction. +func (r *RequiredAction) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RequiredFunctionToolCall. +func (r RequiredFunctionToolCall) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "function", r.Function) + populate(objectMap, "id", r.ID) + objectMap["type"] = "function" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RequiredFunctionToolCall. +func (r *RequiredFunctionToolCall) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "function": + err = unpopulate(val, "Function", &r.Function) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &r.ID) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RequiredFunctionToolCallDetails. +func (r RequiredFunctionToolCallDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "arguments", r.Arguments) + populate(objectMap, "name", r.Name) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RequiredFunctionToolCallDetails. +func (r *RequiredFunctionToolCallDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "arguments": + err = unpopulate(val, "Arguments", &r.Arguments) + delete(rawMsg, key) + case "name": + err = unpopulate(val, "Name", &r.Name) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RequiredToolCall. +func (r RequiredToolCall) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "id", r.ID) + objectMap["type"] = r.Type + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RequiredToolCall. +func (r *RequiredToolCall) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "id": + err = unpopulate(val, "ID", &r.ID) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RetrievalToolDefinition. +func (r RetrievalToolDefinition) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + objectMap["type"] = "retrieval" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RetrievalToolDefinition. +func (r *RetrievalToolDefinition) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunError. +func (r RunError) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "code", r.Code) + populate(objectMap, "message", r.Message) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunError. +func (r *RunError) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "code": + err = unpopulate(val, "Code", &r.Code) + delete(rawMsg, key) + case "message": + err = unpopulate(val, "Message", &r.Message) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStep. +func (r RunStep) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "assistant_id", r.AssistantID) + populateTimeUnix(objectMap, "cancelled_at", r.CancelledAt) + populateTimeUnix(objectMap, "completed_at", r.CompletedAt) + populateTimeUnix(objectMap, "created_at", r.CreatedAt) + populateTimeUnix(objectMap, "expired_at", r.ExpiredAt) + populateTimeUnix(objectMap, "failed_at", r.FailedAt) + populate(objectMap, "id", r.ID) + populate(objectMap, "last_error", r.LastError) + populate(objectMap, "metadata", r.Metadata) + objectMap["object"] = "thread.run.step" + populate(objectMap, "run_id", r.RunID) + populate(objectMap, "status", r.Status) + populate(objectMap, "step_details", r.StepDetails) + populate(objectMap, "thread_id", r.ThreadID) + populate(objectMap, "type", r.Type) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStep. +func (r *RunStep) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "assistant_id": + err = unpopulate(val, "AssistantID", &r.AssistantID) + delete(rawMsg, key) + case "cancelled_at": + err = unpopulateTimeUnix(val, "CancelledAt", &r.CancelledAt) + delete(rawMsg, key) + case "completed_at": + err = unpopulateTimeUnix(val, "CompletedAt", &r.CompletedAt) + delete(rawMsg, key) + case "created_at": + err = unpopulateTimeUnix(val, "CreatedAt", &r.CreatedAt) + delete(rawMsg, key) + case "expired_at": + err = unpopulateTimeUnix(val, "ExpiredAt", &r.ExpiredAt) + delete(rawMsg, key) + case "failed_at": + err = unpopulateTimeUnix(val, "FailedAt", &r.FailedAt) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &r.ID) + delete(rawMsg, key) + case "last_error": + err = unpopulate(val, "LastError", &r.LastError) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &r.Metadata) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &r.Object) + delete(rawMsg, key) + case "run_id": + err = unpopulate(val, "RunID", &r.RunID) + delete(rawMsg, key) + case "status": + err = unpopulate(val, "Status", &r.Status) + delete(rawMsg, key) + case "step_details": + r.StepDetails, err = unmarshalRunStepDetailsClassification(val) + delete(rawMsg, key) + case "thread_id": + err = unpopulate(val, "ThreadID", &r.ThreadID) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepCodeInterpreterImageOutput. +func (r RunStepCodeInterpreterImageOutput) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "image", r.Image) + objectMap["type"] = "image" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepCodeInterpreterImageOutput. +func (r *RunStepCodeInterpreterImageOutput) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "image": + err = unpopulate(val, "Image", &r.Image) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepCodeInterpreterImageReference. +func (r RunStepCodeInterpreterImageReference) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "file_id", r.FileID) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepCodeInterpreterImageReference. +func (r *RunStepCodeInterpreterImageReference) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "file_id": + err = unpopulate(val, "FileID", &r.FileID) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepCodeInterpreterLogOutput. +func (r RunStepCodeInterpreterLogOutput) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "logs", r.Logs) + objectMap["type"] = "logs" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepCodeInterpreterLogOutput. +func (r *RunStepCodeInterpreterLogOutput) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "logs": + err = unpopulate(val, "Logs", &r.Logs) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepCodeInterpreterToolCall. +func (r RunStepCodeInterpreterToolCall) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "code_interpreter", r.CodeInterpreter) + populate(objectMap, "id", r.ID) + objectMap["type"] = "code_interpreter" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepCodeInterpreterToolCall. +func (r *RunStepCodeInterpreterToolCall) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "code_interpreter": + err = unpopulate(val, "CodeInterpreter", &r.CodeInterpreter) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &r.ID) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepCodeInterpreterToolCallDetails. +func (r RunStepCodeInterpreterToolCallDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "input", r.Input) + populate(objectMap, "outputs", r.Outputs) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepCodeInterpreterToolCallDetails. +func (r *RunStepCodeInterpreterToolCallDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "input": + err = unpopulate(val, "Input", &r.Input) + delete(rawMsg, key) + case "outputs": + r.Outputs, err = unmarshalRunStepCodeInterpreterToolCallOutputClassificationArray(val) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepCodeInterpreterToolCallOutput. +func (r RunStepCodeInterpreterToolCallOutput) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + objectMap["type"] = r.Type + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepCodeInterpreterToolCallOutput. +func (r *RunStepCodeInterpreterToolCallOutput) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepDetails. +func (r RunStepDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + objectMap["type"] = r.Type + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepDetails. +func (r *RunStepDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepError. +func (r RunStepError) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "code", r.Code) + populate(objectMap, "message", r.Message) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepError. +func (r *RunStepError) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "code": + err = unpopulate(val, "Code", &r.Code) + delete(rawMsg, key) + case "message": + err = unpopulate(val, "Message", &r.Message) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepFunctionToolCall. +func (r RunStepFunctionToolCall) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "function", r.Function) + populate(objectMap, "id", r.ID) + objectMap["type"] = "function" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepFunctionToolCall. +func (r *RunStepFunctionToolCall) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "function": + err = unpopulate(val, "Function", &r.Function) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &r.ID) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepFunctionToolCallDetails. +func (r RunStepFunctionToolCallDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "arguments", r.Arguments) + populate(objectMap, "name", r.Name) + populate(objectMap, "output", r.Output) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepFunctionToolCallDetails. +func (r *RunStepFunctionToolCallDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "arguments": + err = unpopulate(val, "Arguments", &r.Arguments) + delete(rawMsg, key) + case "name": + err = unpopulate(val, "Name", &r.Name) + delete(rawMsg, key) + case "output": + err = unpopulate(val, "Output", &r.Output) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepLastError. +func (r RunStepLastError) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "code", r.Code) + populate(objectMap, "message", r.Message) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepLastError. +func (r *RunStepLastError) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "code": + err = unpopulate(val, "Code", &r.Code) + delete(rawMsg, key) + case "message": + err = unpopulate(val, "Message", &r.Message) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepMessageCreationDetails. +func (r RunStepMessageCreationDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "message_creation", r.MessageCreation) + objectMap["type"] = RunStepTypeMessageCreation + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepMessageCreationDetails. +func (r *RunStepMessageCreationDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "message_creation": + err = unpopulate(val, "MessageCreation", &r.MessageCreation) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepMessageCreationReference. +func (r RunStepMessageCreationReference) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "message_id", r.MessageID) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepMessageCreationReference. +func (r *RunStepMessageCreationReference) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "message_id": + err = unpopulate(val, "MessageID", &r.MessageID) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepRetrievalToolCall. +func (r RunStepRetrievalToolCall) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "id", r.ID) + populate(objectMap, "retrieval", r.Retrieval) + objectMap["type"] = "retrieval" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepRetrievalToolCall. +func (r *RunStepRetrievalToolCall) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "id": + err = unpopulate(val, "ID", &r.ID) + delete(rawMsg, key) + case "retrieval": + err = unpopulate(val, "Retrieval", &r.Retrieval) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepToolCall. +func (r RunStepToolCall) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "id", r.ID) + objectMap["type"] = r.Type + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepToolCall. +func (r *RunStepToolCall) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "id": + err = unpopulate(val, "ID", &r.ID) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type RunStepToolCallDetails. +func (r RunStepToolCallDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "tool_calls", r.ToolCalls) + objectMap["type"] = RunStepTypeToolCalls + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type RunStepToolCallDetails. +func (r *RunStepToolCallDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "tool_calls": + r.ToolCalls, err = unmarshalRunStepToolCallClassificationArray(val) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &r.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", r, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type SubmitToolOutputsAction. +func (s SubmitToolOutputsAction) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "submit_tool_outputs", s.SubmitToolOutputs) + objectMap["type"] = "submit_tool_outputs" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type SubmitToolOutputsAction. +func (s *SubmitToolOutputsAction) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", s, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "submit_tool_outputs": + err = unpopulate(val, "SubmitToolOutputs", &s.SubmitToolOutputs) + delete(rawMsg, key) + case "type": + err = unpopulate(val, "Type", &s.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", s, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type SubmitToolOutputsDetails. +func (s SubmitToolOutputsDetails) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "tool_calls", s.ToolCalls) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type SubmitToolOutputsDetails. +func (s *SubmitToolOutputsDetails) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", s, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "tool_calls": + s.ToolCalls, err = unmarshalRequiredToolCallClassificationArray(val) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", s, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ThreadDeletionStatus. +func (t ThreadDeletionStatus) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "deleted", t.Deleted) + populate(objectMap, "id", t.ID) + objectMap["object"] = "thread.deleted" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ThreadDeletionStatus. +func (t *ThreadDeletionStatus) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "deleted": + err = unpopulate(val, "Deleted", &t.Deleted) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &t.ID) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &t.Object) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ThreadInitializationMessage. +func (t ThreadInitializationMessage) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "content", t.Content) + populate(objectMap, "file_ids", t.FileIDs) + populate(objectMap, "metadata", t.Metadata) + populate(objectMap, "role", t.Role) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ThreadInitializationMessage. +func (t *ThreadInitializationMessage) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "content": + err = unpopulate(val, "Content", &t.Content) + delete(rawMsg, key) + case "file_ids": + err = unpopulate(val, "FileIDs", &t.FileIDs) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &t.Metadata) + delete(rawMsg, key) + case "role": + err = unpopulate(val, "Role", &t.Role) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ThreadMessage. +func (t ThreadMessage) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "assistant_id", t.AssistantID) + populate(objectMap, "content", t.Content) + populateTimeUnix(objectMap, "created_at", t.CreatedAt) + populate(objectMap, "file_ids", t.FileIDs) + populate(objectMap, "id", t.ID) + populate(objectMap, "metadata", t.Metadata) + objectMap["object"] = "thread.message" + populate(objectMap, "role", t.Role) + populate(objectMap, "run_id", t.RunID) + populate(objectMap, "thread_id", t.ThreadID) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ThreadMessage. +func (t *ThreadMessage) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "assistant_id": + err = unpopulate(val, "AssistantID", &t.AssistantID) + delete(rawMsg, key) + case "content": + t.Content, err = unmarshalMessageContentClassificationArray(val) + delete(rawMsg, key) + case "created_at": + err = unpopulateTimeUnix(val, "CreatedAt", &t.CreatedAt) + delete(rawMsg, key) + case "file_ids": + err = unpopulate(val, "FileIDs", &t.FileIDs) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &t.ID) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &t.Metadata) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &t.Object) + delete(rawMsg, key) + case "role": + err = unpopulate(val, "Role", &t.Role) + delete(rawMsg, key) + case "run_id": + err = unpopulate(val, "RunID", &t.RunID) + delete(rawMsg, key) + case "thread_id": + err = unpopulate(val, "ThreadID", &t.ThreadID) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ThreadRun. +func (t ThreadRun) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "assistant_id", t.AssistantID) + populateTimeUnix(objectMap, "cancelled_at", t.CancelledAt) + populateTimeUnix(objectMap, "completed_at", t.CompletedAt) + populateTimeUnix(objectMap, "created_at", t.CreatedAt) + populateTimeUnix(objectMap, "expires_at", t.ExpiresAt) + populateTimeUnix(objectMap, "failed_at", t.FailedAt) + populate(objectMap, "file_ids", t.FileIDs) + populate(objectMap, "id", t.ID) + populate(objectMap, "instructions", t.Instructions) + populate(objectMap, "last_error", t.LastError) + populate(objectMap, "metadata", t.Metadata) + populate(objectMap, "model", t.DeploymentName) + objectMap["object"] = "thread.run" + populate(objectMap, "required_action", t.RequiredAction) + populateTimeUnix(objectMap, "started_at", t.StartedAt) + populate(objectMap, "status", t.Status) + populate(objectMap, "thread_id", t.ThreadID) + populate(objectMap, "tools", t.Tools) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ThreadRun. +func (t *ThreadRun) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "assistant_id": + err = unpopulate(val, "AssistantID", &t.AssistantID) + delete(rawMsg, key) + case "cancelled_at": + err = unpopulateTimeUnix(val, "CancelledAt", &t.CancelledAt) + delete(rawMsg, key) + case "completed_at": + err = unpopulateTimeUnix(val, "CompletedAt", &t.CompletedAt) + delete(rawMsg, key) + case "created_at": + err = unpopulateTimeUnix(val, "CreatedAt", &t.CreatedAt) + delete(rawMsg, key) + case "expires_at": + err = unpopulateTimeUnix(val, "ExpiresAt", &t.ExpiresAt) + delete(rawMsg, key) + case "failed_at": + err = unpopulateTimeUnix(val, "FailedAt", &t.FailedAt) + delete(rawMsg, key) + case "file_ids": + err = unpopulate(val, "FileIDs", &t.FileIDs) + delete(rawMsg, key) + case "id": + err = unpopulate(val, "ID", &t.ID) + delete(rawMsg, key) + case "instructions": + err = unpopulate(val, "Instructions", &t.Instructions) + delete(rawMsg, key) + case "last_error": + err = unpopulate(val, "LastError", &t.LastError) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &t.Metadata) + delete(rawMsg, key) + case "model": + err = unpopulate(val, "Model", &t.DeploymentName) + delete(rawMsg, key) + case "object": + err = unpopulate(val, "Object", &t.Object) + delete(rawMsg, key) + case "required_action": + err = unpopulate(val, "RequiredAction", &t.RequiredAction) + delete(rawMsg, key) + case "started_at": + err = unpopulateTimeUnix(val, "StartedAt", &t.StartedAt) + delete(rawMsg, key) + case "status": + err = unpopulate(val, "Status", &t.Status) + delete(rawMsg, key) + case "thread_id": + err = unpopulate(val, "ThreadID", &t.ThreadID) + delete(rawMsg, key) + case "tools": + t.Tools, err = unmarshalToolDefinitionClassificationArray(val) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ThreadRunLastError. +func (t ThreadRunLastError) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "code", t.Code) + populate(objectMap, "message", t.Message) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ThreadRunLastError. +func (t *ThreadRunLastError) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "code": + err = unpopulate(val, "Code", &t.Code) + delete(rawMsg, key) + case "message": + err = unpopulate(val, "Message", &t.Message) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ThreadRunRequiredAction. +func (t ThreadRunRequiredAction) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + objectMap["type"] = "ThreadRun-required_action" + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ThreadRunRequiredAction. +func (t *ThreadRunRequiredAction) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "type": + err = unpopulate(val, "Type", &t.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ToolDefinition. +func (t ToolDefinition) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + objectMap["type"] = t.Type + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ToolDefinition. +func (t *ToolDefinition) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "type": + err = unpopulate(val, "Type", &t.Type) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type ToolOutput. +func (t ToolOutput) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "output", t.Output) + populate(objectMap, "tool_call_id", t.ToolCallID) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type ToolOutput. +func (t *ToolOutput) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "output": + err = unpopulate(val, "Output", &t.Output) + delete(rawMsg, key) + case "tool_call_id": + err = unpopulate(val, "ToolCallID", &t.ToolCallID) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", t, err) + } + } + return nil +} + +// MarshalJSON implements the json.Marshaller interface for type UpdateAssistantBody. +func (u UpdateAssistantBody) MarshalJSON() ([]byte, error) { + objectMap := make(map[string]any) + populate(objectMap, "description", u.Description) + populate(objectMap, "file_ids", u.FileIDs) + populate(objectMap, "instructions", u.Instructions) + populate(objectMap, "metadata", u.Metadata) + populate(objectMap, "model", u.DeploymentName) + populate(objectMap, "name", u.Name) + populate(objectMap, "tools", u.Tools) + return json.Marshal(objectMap) +} + +// UnmarshalJSON implements the json.Unmarshaller interface for type UpdateAssistantBody. +func (u *UpdateAssistantBody) UnmarshalJSON(data []byte) error { + var rawMsg map[string]json.RawMessage + if err := json.Unmarshal(data, &rawMsg); err != nil { + return fmt.Errorf("unmarshalling type %T: %v", u, err) + } + for key, val := range rawMsg { + var err error + switch key { + case "description": + err = unpopulate(val, "Description", &u.Description) + delete(rawMsg, key) + case "file_ids": + err = unpopulate(val, "FileIDs", &u.FileIDs) + delete(rawMsg, key) + case "instructions": + err = unpopulate(val, "Instructions", &u.Instructions) + delete(rawMsg, key) + case "metadata": + err = unpopulate(val, "Metadata", &u.Metadata) + delete(rawMsg, key) + case "model": + err = unpopulate(val, "Model", &u.DeploymentName) + delete(rawMsg, key) + case "name": + err = unpopulate(val, "Name", &u.Name) + delete(rawMsg, key) + case "tools": + u.Tools, err = unmarshalToolDefinitionClassificationArray(val) + delete(rawMsg, key) + } + if err != nil { + return fmt.Errorf("unmarshalling type %T: %v", u, err) + } + } + return nil +} + +func populate(m map[string]any, k string, v any) { + if v == nil { + return + } else if azcore.IsNullValue(v) { + m[k] = nil + } else if !reflect.ValueOf(v).IsNil() { + m[k] = v + } +} + +func populateAny(m map[string]any, k string, v any) { + if v == nil { + return + } else if azcore.IsNullValue(v) { + m[k] = nil + } else { + m[k] = v + } +} + +func unpopulate(data json.RawMessage, fn string, v any) error { + if data == nil || string(data) == "null" { + return nil + } + if err := json.Unmarshal(data, v); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + return nil +} diff --git a/sdk/ai/azopenaiassistants/options.go b/sdk/ai/azopenaiassistants/options.go new file mode 100644 index 000000000000..f6d6c51ba3bf --- /dev/null +++ b/sdk/ai/azopenaiassistants/options.go @@ -0,0 +1,255 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +// CancelRunOptions contains the optional parameters for the Client.CancelRun method. +type CancelRunOptions struct { + // placeholder for future optional parameters +} + +// CreateAssistantFileOptions contains the optional parameters for the Client.CreateAssistantFile method. +type CreateAssistantFileOptions struct { + // placeholder for future optional parameters +} + +// CreateAssistantOptions contains the optional parameters for the Client.CreateAssistant method. +type CreateAssistantOptions struct { + // placeholder for future optional parameters +} + +// CreateMessageOptions contains the optional parameters for the Client.CreateMessage method. +type CreateMessageOptions struct { + // placeholder for future optional parameters +} + +// CreateRunOptions contains the optional parameters for the Client.CreateRun method. +type CreateRunOptions struct { + // placeholder for future optional parameters +} + +// CreateThreadAndRunOptions contains the optional parameters for the Client.CreateThreadAndRun method. +type CreateThreadAndRunOptions struct { + // placeholder for future optional parameters +} + +// CreateThreadOptions contains the optional parameters for the Client.CreateThread method. +type CreateThreadOptions struct { + // placeholder for future optional parameters +} + +// DeleteAssistantFileOptions contains the optional parameters for the Client.DeleteAssistantFile method. +type DeleteAssistantFileOptions struct { + // placeholder for future optional parameters +} + +// DeleteAssistantOptions contains the optional parameters for the Client.DeleteAssistant method. +type DeleteAssistantOptions struct { + // placeholder for future optional parameters +} + +// DeleteFileOptions contains the optional parameters for the Client.DeleteFile method. +type DeleteFileOptions struct { + // placeholder for future optional parameters +} + +// DeleteThreadOptions contains the optional parameters for the Client.DeleteThread method. +type DeleteThreadOptions struct { + // placeholder for future optional parameters +} + +// GetAssistantFileOptions contains the optional parameters for the Client.GetAssistantFile method. +type GetAssistantFileOptions struct { + // placeholder for future optional parameters +} + +// GetAssistantOptions contains the optional parameters for the Client.GetAssistant method. +type GetAssistantOptions struct { + // placeholder for future optional parameters +} + +// GetFileOptions contains the optional parameters for the Client.GetFile method. +type GetFileOptions struct { + // placeholder for future optional parameters +} + +// GetMessageFileOptions contains the optional parameters for the Client.GetMessageFile method. +type GetMessageFileOptions struct { + // placeholder for future optional parameters +} + +// GetMessageOptions contains the optional parameters for the Client.GetMessage method. +type GetMessageOptions struct { + // placeholder for future optional parameters +} + +// GetRunOptions contains the optional parameters for the Client.GetRun method. +type GetRunOptions struct { + // placeholder for future optional parameters +} + +// GetRunStepOptions contains the optional parameters for the Client.GetRunStep method. +type GetRunStepOptions struct { + // placeholder for future optional parameters +} + +// GetThreadOptions contains the optional parameters for the Client.GetThread method. +type GetThreadOptions struct { + // placeholder for future optional parameters +} + +// ListAssistantFilesOptions contains the optional parameters for the Client.ListAssistantFiles method. +type ListAssistantFilesOptions struct { + // A 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 objfoo, your subsequent call + // can include after=objfoo in order to fetch the next page of the list. + After *string + + // A 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, ending with objfoo, your subsequent call + // can include before=objfoo in order to fetch the previous page of the list. + Before *string + + // A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + Limit *int32 + + // Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order. + Order *ListSortOrder +} + +// ListAssistantsOptions contains the optional parameters for the Client.ListAssistants method. +type ListAssistantsOptions struct { + // A 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 objfoo, your subsequent call + // can include after=objfoo in order to fetch the next page of the list. + After *string + + // A 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, ending with objfoo, your subsequent call + // can include before=objfoo in order to fetch the previous page of the list. + Before *string + + // A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + Limit *int32 + + // Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order. + Order *ListSortOrder +} + +// ListFilesOptions contains the optional parameters for the Client.ListFiles method. +type ListFilesOptions struct { + // A value that, when provided, limits list results to files matching the corresponding purpose. + Purpose *FilePurpose +} + +// ListMessageFilesOptions contains the optional parameters for the Client.ListMessageFiles method. +type ListMessageFilesOptions struct { + // A 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 objfoo, your subsequent call + // can include after=objfoo in order to fetch the next page of the list. + After *string + + // A 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, ending with objfoo, your subsequent call + // can include before=objfoo in order to fetch the previous page of the list. + Before *string + + // A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + Limit *int32 + + // Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order. + Order *ListSortOrder +} + +// ListMessagesOptions contains the optional parameters for the Client.ListMessages method. +type ListMessagesOptions struct { + // A 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 objfoo, your subsequent call + // can include after=objfoo in order to fetch the next page of the list. + After *string + + // A 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, ending with objfoo, your subsequent call + // can include before=objfoo in order to fetch the previous page of the list. + Before *string + + // A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + Limit *int32 + + // Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order. + Order *ListSortOrder +} + +// ListRunStepsOptions contains the optional parameters for the Client.ListRunSteps method. +type ListRunStepsOptions struct { + // A 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 objfoo, your subsequent call + // can include after=objfoo in order to fetch the next page of the list. + After *string + + // A 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, ending with objfoo, your subsequent call + // can include before=objfoo in order to fetch the previous page of the list. + Before *string + + // A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + Limit *int32 + + // Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order. + Order *ListSortOrder +} + +// ListRunsOptions contains the optional parameters for the Client.ListRuns method. +type ListRunsOptions struct { + // A 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 objfoo, your subsequent call + // can include after=objfoo in order to fetch the next page of the list. + After *string + + // A 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, ending with objfoo, your subsequent call + // can include before=objfoo in order to fetch the previous page of the list. + Before *string + + // A limit on the number of objects to be returned. Limit can range between 1 and 100, and the default is 20. + Limit *int32 + + // Sort order by the created_at timestamp of the objects. asc for ascending order and desc for descending order. + Order *ListSortOrder +} + +// SubmitToolOutputsToRunOptions contains the optional parameters for the Client.SubmitToolOutputsToRun method. +type SubmitToolOutputsToRunOptions struct { + // placeholder for future optional parameters +} + +// UpdateAssistantOptions contains the optional parameters for the Client.UpdateAssistant method. +type UpdateAssistantOptions struct { + // placeholder for future optional parameters +} + +// UpdateMessageOptions contains the optional parameters for the Client.UpdateMessage method. +type UpdateMessageOptions struct { + // placeholder for future optional parameters +} + +// UpdateRunOptions contains the optional parameters for the Client.UpdateRun method. +type UpdateRunOptions struct { + // placeholder for future optional parameters +} + +// UpdateThreadOptions contains the optional parameters for the Client.UpdateThread method. +type UpdateThreadOptions struct { + // placeholder for future optional parameters +} + +// UploadFileOptions contains the optional parameters for the Client.UploadFile method. +type UploadFileOptions struct { + // A filename to associate with the uploaded data. + Filename *string +} diff --git a/sdk/ai/azopenaiassistants/polymorphic_helpers.go b/sdk/ai/azopenaiassistants/polymorphic_helpers.go new file mode 100644 index 000000000000..590f741d5fb7 --- /dev/null +++ b/sdk/ai/azopenaiassistants/polymorphic_helpers.go @@ -0,0 +1,288 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +import "encoding/json" + +func unmarshalMessageContentClassification(rawMsg json.RawMessage) (MessageContentClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var m map[string]any + if err := json.Unmarshal(rawMsg, &m); err != nil { + return nil, err + } + var b MessageContentClassification + switch m["type"] { + case "image_file": + b = &MessageImageFileContent{} + case "text": + b = &MessageTextContent{} + default: + b = &MessageContent{} + } + if err := json.Unmarshal(rawMsg, b); err != nil { + return nil, err + } + return b, nil +} + +func unmarshalMessageContentClassificationArray(rawMsg json.RawMessage) ([]MessageContentClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var rawMessages []json.RawMessage + if err := json.Unmarshal(rawMsg, &rawMessages); err != nil { + return nil, err + } + fArray := make([]MessageContentClassification, len(rawMessages)) + for index, rawMessage := range rawMessages { + f, err := unmarshalMessageContentClassification(rawMessage) + if err != nil { + return nil, err + } + fArray[index] = f + } + return fArray, nil +} + +func unmarshalMessageTextAnnotationClassification(rawMsg json.RawMessage) (MessageTextAnnotationClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var m map[string]any + if err := json.Unmarshal(rawMsg, &m); err != nil { + return nil, err + } + var b MessageTextAnnotationClassification + switch m["type"] { + case "file_citation": + b = &MessageTextFileCitationAnnotation{} + case "file_path": + b = &MessageTextFilePathAnnotation{} + default: + b = &MessageTextAnnotation{} + } + if err := json.Unmarshal(rawMsg, b); err != nil { + return nil, err + } + return b, nil +} + +func unmarshalMessageTextAnnotationClassificationArray(rawMsg json.RawMessage) ([]MessageTextAnnotationClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var rawMessages []json.RawMessage + if err := json.Unmarshal(rawMsg, &rawMessages); err != nil { + return nil, err + } + fArray := make([]MessageTextAnnotationClassification, len(rawMessages)) + for index, rawMessage := range rawMessages { + f, err := unmarshalMessageTextAnnotationClassification(rawMessage) + if err != nil { + return nil, err + } + fArray[index] = f + } + return fArray, nil +} + +func unmarshalRequiredToolCallClassification(rawMsg json.RawMessage) (RequiredToolCallClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var m map[string]any + if err := json.Unmarshal(rawMsg, &m); err != nil { + return nil, err + } + var b RequiredToolCallClassification + switch m["type"] { + case "function": + b = &RequiredFunctionToolCall{} + default: + b = &RequiredToolCall{} + } + if err := json.Unmarshal(rawMsg, b); err != nil { + return nil, err + } + return b, nil +} + +func unmarshalRequiredToolCallClassificationArray(rawMsg json.RawMessage) ([]RequiredToolCallClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var rawMessages []json.RawMessage + if err := json.Unmarshal(rawMsg, &rawMessages); err != nil { + return nil, err + } + fArray := make([]RequiredToolCallClassification, len(rawMessages)) + for index, rawMessage := range rawMessages { + f, err := unmarshalRequiredToolCallClassification(rawMessage) + if err != nil { + return nil, err + } + fArray[index] = f + } + return fArray, nil +} + +func unmarshalRunStepCodeInterpreterToolCallOutputClassification(rawMsg json.RawMessage) (RunStepCodeInterpreterToolCallOutputClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var m map[string]any + if err := json.Unmarshal(rawMsg, &m); err != nil { + return nil, err + } + var b RunStepCodeInterpreterToolCallOutputClassification + switch m["type"] { + case "image": + b = &RunStepCodeInterpreterImageOutput{} + case "logs": + b = &RunStepCodeInterpreterLogOutput{} + default: + b = &RunStepCodeInterpreterToolCallOutput{} + } + if err := json.Unmarshal(rawMsg, b); err != nil { + return nil, err + } + return b, nil +} + +func unmarshalRunStepCodeInterpreterToolCallOutputClassificationArray(rawMsg json.RawMessage) ([]RunStepCodeInterpreterToolCallOutputClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var rawMessages []json.RawMessage + if err := json.Unmarshal(rawMsg, &rawMessages); err != nil { + return nil, err + } + fArray := make([]RunStepCodeInterpreterToolCallOutputClassification, len(rawMessages)) + for index, rawMessage := range rawMessages { + f, err := unmarshalRunStepCodeInterpreterToolCallOutputClassification(rawMessage) + if err != nil { + return nil, err + } + fArray[index] = f + } + return fArray, nil +} + +func unmarshalRunStepDetailsClassification(rawMsg json.RawMessage) (RunStepDetailsClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var m map[string]any + if err := json.Unmarshal(rawMsg, &m); err != nil { + return nil, err + } + var b RunStepDetailsClassification + switch m["type"] { + case string(RunStepTypeMessageCreation): + b = &RunStepMessageCreationDetails{} + case string(RunStepTypeToolCalls): + b = &RunStepToolCallDetails{} + default: + b = &RunStepDetails{} + } + if err := json.Unmarshal(rawMsg, b); err != nil { + return nil, err + } + return b, nil +} + +func unmarshalRunStepToolCallClassification(rawMsg json.RawMessage) (RunStepToolCallClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var m map[string]any + if err := json.Unmarshal(rawMsg, &m); err != nil { + return nil, err + } + var b RunStepToolCallClassification + switch m["type"] { + case "code_interpreter": + b = &RunStepCodeInterpreterToolCall{} + case "function": + b = &RunStepFunctionToolCall{} + case "retrieval": + b = &RunStepRetrievalToolCall{} + default: + b = &RunStepToolCall{} + } + if err := json.Unmarshal(rawMsg, b); err != nil { + return nil, err + } + return b, nil +} + +func unmarshalRunStepToolCallClassificationArray(rawMsg json.RawMessage) ([]RunStepToolCallClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var rawMessages []json.RawMessage + if err := json.Unmarshal(rawMsg, &rawMessages); err != nil { + return nil, err + } + fArray := make([]RunStepToolCallClassification, len(rawMessages)) + for index, rawMessage := range rawMessages { + f, err := unmarshalRunStepToolCallClassification(rawMessage) + if err != nil { + return nil, err + } + fArray[index] = f + } + return fArray, nil +} + +func unmarshalToolDefinitionClassification(rawMsg json.RawMessage) (ToolDefinitionClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var m map[string]any + if err := json.Unmarshal(rawMsg, &m); err != nil { + return nil, err + } + var b ToolDefinitionClassification + switch m["type"] { + case "code_interpreter": + b = &CodeInterpreterToolDefinition{} + case "function": + b = &FunctionToolDefinition{} + case "retrieval": + b = &RetrievalToolDefinition{} + default: + b = &ToolDefinition{} + } + if err := json.Unmarshal(rawMsg, b); err != nil { + return nil, err + } + return b, nil +} + +func unmarshalToolDefinitionClassificationArray(rawMsg json.RawMessage) ([]ToolDefinitionClassification, error) { + if rawMsg == nil || string(rawMsg) == "null" { + return nil, nil + } + var rawMessages []json.RawMessage + if err := json.Unmarshal(rawMsg, &rawMessages); err != nil { + return nil, err + } + fArray := make([]ToolDefinitionClassification, len(rawMessages)) + for index, rawMessage := range rawMessages { + f, err := unmarshalToolDefinitionClassification(rawMessage) + if err != nil { + return nil, err + } + fArray[index] = f + } + return fArray, nil +} diff --git a/sdk/ai/azopenaiassistants/responses.go b/sdk/ai/azopenaiassistants/responses.go new file mode 100644 index 000000000000..b8db16dab264 --- /dev/null +++ b/sdk/ai/azopenaiassistants/responses.go @@ -0,0 +1,201 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +// CancelRunResponse contains the response from method Client.CancelRun. +type CancelRunResponse struct { + // Data representing a single evaluation run of an assistant thread. + ThreadRun +} + +// CreateAssistantFileResponse contains the response from method Client.CreateAssistantFile. +type CreateAssistantFileResponse struct { + // Information about a file attached to an assistant, as used by tools that can read files. + AssistantFile +} + +// CreateAssistantResponse contains the response from method Client.CreateAssistant. +type CreateAssistantResponse struct { + // Represents an assistant that can call the model and use tools. + Assistant +} + +// CreateMessageResponse contains the response from method Client.CreateMessage. +type CreateMessageResponse struct { + // A single, existing message within an assistant thread. + ThreadMessage +} + +// CreateRunResponse contains the response from method Client.CreateRun. +type CreateRunResponse struct { + // Data representing a single evaluation run of an assistant thread. + ThreadRun +} + +// CreateThreadAndRunResponse contains the response from method Client.CreateThreadAndRun. +type CreateThreadAndRunResponse struct { + // Data representing a single evaluation run of an assistant thread. + ThreadRun +} + +// CreateThreadResponse contains the response from method Client.CreateThread. +type CreateThreadResponse struct { + // Information about a single thread associated with an assistant. + AssistantThread +} + +// DeleteAssistantFileResponse contains the response from method Client.DeleteAssistantFile. +type DeleteAssistantFileResponse struct { + // The status of an assistant file deletion operation. + AssistantFileDeletionStatus +} + +// DeleteAssistantResponse contains the response from method Client.DeleteAssistant. +type DeleteAssistantResponse struct { + // The status of an assistant deletion operation. + AssistantDeletionStatus +} + +// DeleteFileResponse contains the response from method Client.DeleteFile. +type DeleteFileResponse struct { + // A status response from a file deletion operation. + FileDeletionStatus +} + +// DeleteThreadResponse contains the response from method Client.DeleteThread. +type DeleteThreadResponse struct { + // The status of a thread deletion operation. + ThreadDeletionStatus +} + +// GetAssistantFileResponse contains the response from method Client.GetAssistantFile. +type GetAssistantFileResponse struct { + // Information about a file attached to an assistant, as used by tools that can read files. + AssistantFile +} + +// GetAssistantResponse contains the response from method Client.GetAssistant. +type GetAssistantResponse struct { + // Represents an assistant that can call the model and use tools. + Assistant +} + +// GetFileResponse contains the response from method Client.GetFile. +type GetFileResponse struct { + // Represents an assistant that can call the model and use tools. + OpenAIFile +} + +// GetMessageFileResponse contains the response from method Client.GetMessageFile. +type GetMessageFileResponse struct { + // Information about a file attached to an assistant thread message. + MessageFile +} + +// GetMessageResponse contains the response from method Client.GetMessage. +type GetMessageResponse struct { + // A single, existing message within an assistant thread. + ThreadMessage +} + +// GetRunResponse contains the response from method Client.GetRun. +type GetRunResponse struct { + // Data representing a single evaluation run of an assistant thread. + ThreadRun +} + +// GetRunStepResponse contains the response from method Client.GetRunStep. +type GetRunStepResponse struct { + // Detailed information about a single step of an assistant thread run. + RunStep +} + +// GetThreadResponse contains the response from method Client.GetThread. +type GetThreadResponse struct { + // Information about a single thread associated with an assistant. + AssistantThread +} + +// ListAssistantFilesResponse contains the response from method Client.ListAssistantFiles. +type ListAssistantFilesResponse struct { + // The response data for a requested list of items. + AssistantFilesPage +} + +// ListAssistantsResponse contains the response from method Client.ListAssistants. +type ListAssistantsResponse struct { + // The response data for a requested list of items. + AssistantsPage +} + +// ListFilesResponse contains the response from method Client.ListFiles. +type ListFilesResponse struct { + // The response data from a file list operation. + FileListResponse +} + +// ListMessageFilesResponse contains the response from method Client.ListMessageFiles. +type ListMessageFilesResponse struct { + // The response data for a requested list of items. + MessageFilesPage +} + +// ListMessagesResponse contains the response from method Client.ListMessages. +type ListMessagesResponse struct { + // The response data for a requested list of items. + MessagesPage +} + +// ListRunStepsResponse contains the response from method Client.ListRunSteps. +type ListRunStepsResponse struct { + // The response data for a requested list of items. + RunStepsPage +} + +// ListRunsResponse contains the response from method Client.ListRuns. +type ListRunsResponse struct { + // The response data for a requested list of items. + ThreadRunsPage +} + +// SubmitToolOutputsToRunResponse contains the response from method Client.SubmitToolOutputsToRun. +type SubmitToolOutputsToRunResponse struct { + // Data representing a single evaluation run of an assistant thread. + ThreadRun +} + +// UpdateAssistantResponse contains the response from method Client.UpdateAssistant. +type UpdateAssistantResponse struct { + // Represents an assistant that can call the model and use tools. + Assistant +} + +// UpdateMessageResponse contains the response from method Client.UpdateMessage. +type UpdateMessageResponse struct { + // A single, existing message within an assistant thread. + ThreadMessage +} + +// UpdateRunResponse contains the response from method Client.UpdateRun. +type UpdateRunResponse struct { + // Data representing a single evaluation run of an assistant thread. + ThreadRun +} + +// UpdateThreadResponse contains the response from method Client.UpdateThread. +type UpdateThreadResponse struct { + // Information about a single thread associated with an assistant. + AssistantThread +} + +// UploadFileResponse contains the response from method Client.UploadFile. +type UploadFileResponse struct { + // Represents an assistant that can call the model and use tools. + OpenAIFile +} diff --git a/sdk/ai/azopenaiassistants/shared_test.go b/sdk/ai/azopenaiassistants/shared_test.go new file mode 100644 index 000000000000..1e0ba943815b --- /dev/null +++ b/sdk/ai/azopenaiassistants/shared_test.go @@ -0,0 +1,287 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants_test + +import ( + "bytes" + "context" + "crypto/tls" + "errors" + "fmt" + "io" + "mime" + "net/http" + "os" + "strings" + "testing" + + "github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants" + assistants "github.com/Azure/azure-sdk-for-go/sdk/ai/azopenaiassistants" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/policy" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/streaming" + "github.com/Azure/azure-sdk-for-go/sdk/azcore/to" + "github.com/Azure/azure-sdk-for-go/sdk/azidentity" + "github.com/Azure/azure-sdk-for-go/sdk/internal/recording" + "github.com/stretchr/testify/require" +) + +func stringize(v azopenaiassistants.MessageContentClassification) string { + switch m := v.(type) { + case *azopenaiassistants.MessageTextContent: + return fmt.Sprintf("Text = %s\n", *m.Text.Value) + case *azopenaiassistants.MessageImageFileContent: + return fmt.Sprintf("Image = %s\n", *m.ImageFile.FileID) + } + + panic("Unhandled type for stringizing") +} + +type mustGetClientWithAssistantArgs struct { + newClientArgs + Instructions string +} + +type newClientArgs struct { + Azure bool + UseIdentity bool +} + +func newClient(t *testing.T, args newClientArgs) *azopenaiassistants.Client { + var httpClient policy.Transporter + // var recordingPolicy + // PerRetryPolicies: []{&mimeTypeRecordingPolicy{}} + var perRetryPolicy policy.Policy + + if recording.GetRecordMode() != recording.LiveMode { + err := recording.Start(t, RecordingDirectory, nil) + require.NoError(t, err) + + t.Cleanup(func() { + err := recording.Stop(t, nil) + require.NoError(t, err) + }) + + tmpHttpClient, err := recording.NewRecordingHTTPClient(t, nil) + require.NoError(t, err) + + if recording.GetRecordMode() == recording.RecordingMode { + err = recording.AddURISanitizer("https://openai.azure.com", strings.TrimRight(tv.AOAIEndpoint, "/"), nil) + require.NoError(t, err) + + err = recording.AddURISanitizer("https://openai.azure.com", strings.TrimRight(tv.OpenAIEndpoint, "/"), nil) + require.NoError(t, err) + + err = recording.AddHeaderRegexSanitizer("Api-Key", "key", "", nil) + require.NoError(t, err) + } + + httpClient = tmpHttpClient + perRetryPolicy = &mimeTypeRecordingPolicy{} + } else if os.Getenv("SSLKEYLOGFILE") != "" { + file, err := os.OpenFile(os.Getenv("SSLKEYLOGFILE"), os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0700) + require.NoError(t, err) + + t.Cleanup(func() { + err := file.Close() + require.NoError(t, err) + }) + + transport := http.DefaultTransport.(*http.Transport).Clone() + transport.TLSClientConfig = &tls.Config{ + KeyLogWriter: file, + } + httpClient = &http.Client{Transport: transport} + } + + opts := &azopenaiassistants.ClientOptions{ + ClientOptions: policy.ClientOptions{ + Logging: policy.LogOptions{ + IncludeBody: true, + }, + Transport: httpClient, + }, + } + + if perRetryPolicy != nil { + opts.PerRetryPolicies = append(opts.PerRetryPolicies, perRetryPolicy) + } + + if args.Azure { + if args.UseIdentity { + dac, err := azidentity.NewDefaultAzureCredential(nil) + require.NoError(t, err) + + tmpClient, err := azopenaiassistants.NewClient(tv.AOAIEndpoint, dac, opts) + require.NoError(t, err) + return tmpClient + } else { + tmpClient, err := azopenaiassistants.NewClientWithKeyCredential(tv.AOAIEndpoint, azcore.NewKeyCredential(tv.AOAIKey), opts) + require.NoError(t, err) + return tmpClient + } + } else { + tmpClient, err := azopenaiassistants.NewClientForOpenAI(tv.OpenAIEndpoint, azcore.NewKeyCredential(tv.OpenAIKey), opts) + require.NoError(t, err) + return tmpClient + } +} + +func mustGetClientWithAssistant(t *testing.T, args mustGetClientWithAssistantArgs) (*azopenaiassistants.Client, azopenaiassistants.CreateAssistantResponse) { + client := newClient(t, args.newClientArgs) + + // give the assistant a random-ish name. + id, err := recording.GenerateAlphaNumericID(t, "your-assistant-name", 6+len("your-assistant-name"), true) + require.NoError(t, err) + + assistantName := id + + createResp, err := client.CreateAssistant(context.Background(), azopenaiassistants.AssistantCreationBody{ + Name: &assistantName, + DeploymentName: &assistantsModel, + Instructions: to.Ptr("You are a personal math tutor. Write and run code to answer math questions."), + Tools: []assistants.ToolDefinitionClassification{ + &assistants.CodeInterpreterToolDefinition{}, + + // others... + // &assistants.FunctionToolDefinition{} + // &assistants.RetrievalToolDefinition{} + }, + }, nil) + require.NoError(t, err) + + t.Cleanup(func() { + _, err := client.DeleteAssistant(context.Background(), *createResp.ID, nil) + require.NoError(t, err) + }) + + return client, createResp +} + +type runThreadArgs struct { + newClientArgs + Assistant azopenaiassistants.AssistantCreationBody + Thread azopenaiassistants.CreateAndRunThreadOptions +} + +func mustRunThread(ctx context.Context, t *testing.T, args runThreadArgs) (*azopenaiassistants.Client, []azopenaiassistants.ThreadMessage) { + client := newClient(t, args.newClientArgs) + + // give the assistant a random-ish name. + assistantName, err := recording.GenerateAlphaNumericID(t, "your-assistant-name", 6+len("your-assistant-name"), true) + require.NoError(t, err) + + if args.Assistant.Name == nil { + args.Assistant.Name = &assistantName + } + + args.Assistant.DeploymentName = &assistantsModel + + createResp, err := client.CreateAssistant(ctx, args.Assistant, nil) + require.NoError(t, err) + + t.Cleanup(func() { + _, err := client.DeleteAssistant(ctx, *createResp.ID, nil) + require.NoError(t, err) + }) + + // create a thread and run it + args.Thread.AssistantID = createResp.ID + threadRunResp, err := client.CreateThreadAndRun(ctx, args.Thread, nil) + require.NoError(t, err) + + // poll for the thread end + err = pollRunEnd(ctx, client, *threadRunResp.ThreadID, *threadRunResp.ID) + require.NoError(t, err) + + var allMessages []azopenaiassistants.ThreadMessage + + messagePager := client.NewListMessagesPager(*threadRunResp.ThreadID, &assistants.ListMessagesOptions{ + Order: to.Ptr(azopenaiassistants.ListSortOrderAscending), + }) + + for messagePager.More() { + page, err := messagePager.NextPage(ctx) + require.NoError(t, err) + + allMessages = append(allMessages, page.Data...) + } + + return client, allMessages +} + +func mustUploadFile(t *testing.T, c *assistants.Client, text string) azopenaiassistants.UploadFileResponse { + textBytes := []byte(text) + + uploadResp, err := c.UploadFile(context.Background(), bytes.NewReader(textBytes), azopenaiassistants.FilePurposeAssistants, &assistants.UploadFileOptions{ + Filename: to.Ptr("a.txt"), + }) + require.NoError(t, err) + require.Equal(t, len(textBytes), int(*uploadResp.Bytes)) + + t.Cleanup(func() { + _, err := c.DeleteFile(context.Background(), *uploadResp.ID, nil) + require.NoError(t, err) + }) + + return uploadResp +} + +type mimeTypeRecordingPolicy struct{} + +// Do changes out the boundary for a multipart message. This makes it simpler to write +// recordings. +func (mrp *mimeTypeRecordingPolicy) Do(req *policy.Request) (*http.Response, error) { + if recording.GetRecordMode() == recording.LiveMode { + // this is strictly to make the IDs in the multipart body stable for test recordings. + return req.Next() + } + + // we'll fix up the multipart to make it more predictable for test recordings. + // Content-Type: multipart/form-data; boundary=787c880ce3dd11f9b6384d625c399c8490fc8989ceb6b7d208ec7426c12e + + contentType := req.Raw().Header[http.CanonicalHeaderKey("Content-type")] + + if len(contentType) == 0 { + return req.Next() + } + + mediaType, params, err := mime.ParseMediaType(contentType[0]) + + if err != nil || mediaType != "multipart/form-data" { + // we'll just assume our policy doesn't apply here. + return req.Next() + } + + origBoundary := params["boundary"] + + if origBoundary == "" { + return nil, errors.New("Invalid use of this policy - no boundary was passed as part of the multipart mime type") + } + + params["boundary"] = "boundary-for-recordings" + + // now let's update the body itself - we'll just do a simple string replacement. The entire purpose of the boundary string is to provide a + // separator, which is distinct from the content. + body := req.Body() + defer body.Close() + + origBody, err := io.ReadAll(body) + + if err != nil { + return nil, err + } + + newBody := bytes.ReplaceAll(origBody, []byte(origBoundary), []byte("boundary-for-recordings")) + + if err := req.SetBody(streaming.NopCloser(bytes.NewReader(newBody)), mime.FormatMediaType(mediaType, params)); err != nil { + return nil, err + } + + return req.Next() +} diff --git a/sdk/ai/azopenaiassistants/test-resources.bicep b/sdk/ai/azopenaiassistants/test-resources.bicep new file mode 100644 index 000000000000..27bd1e92356b --- /dev/null +++ b/sdk/ai/azopenaiassistants/test-resources.bicep @@ -0,0 +1,10 @@ +// This is a placeholder file to trigger environment variable setting via New-TestResources.ps1 + +@description('The base resource name.') +param baseName string = resourceGroup().name + +@description('Which Azure Region to deploy the resource to. Defaults to the resource group location.') +param location string = resourceGroup().location + +@description('The principal to assign the role to. This is application object id.') +param testApplicationOid string diff --git a/sdk/ai/azopenaiassistants/testdata/.gitignore b/sdk/ai/azopenaiassistants/testdata/.gitignore new file mode 100644 index 000000000000..75254e2c4d3c --- /dev/null +++ b/sdk/ai/azopenaiassistants/testdata/.gitignore @@ -0,0 +1,3 @@ +node_modules +generated +TempTypeSpecFiles \ No newline at end of file diff --git a/sdk/ai/azopenaiassistants/testdata/genopenapi.ps1 b/sdk/ai/azopenaiassistants/testdata/genopenapi.ps1 new file mode 100644 index 000000000000..54d116af50f1 --- /dev/null +++ b/sdk/ai/azopenaiassistants/testdata/genopenapi.ps1 @@ -0,0 +1,37 @@ +Push-Location ./testdata + +if (Test-Path -Path "TempTypeSpecFiles") { + Remove-Item -Recurse -Force TempTypeSpecFiles +} + +npm install + +if ($LASTEXITCODE -ne 0) { + Exit 1 +} + +npm run pull + +if ($LASTEXITCODE -ne 0) { + Exit 1 +} + +npm run build + +if ($LASTEXITCODE -ne 0) { + Exit 1 +} + +Pop-Location + +autorest ./autorest.md + +if ($LASTEXITCODE -ne 0) { + Exit 1 +} + +goimports -w ./.. + +if ($LASTEXITCODE -ne 0) { + Exit 1 +} diff --git a/sdk/ai/azopenaiassistants/testdata/package-lock.json b/sdk/ai/azopenaiassistants/testdata/package-lock.json new file mode 100644 index 000000000000..49d4e237d402 --- /dev/null +++ b/sdk/ai/azopenaiassistants/testdata/package-lock.json @@ -0,0 +1,893 @@ +{ + "name": "testdata", + "version": "0.1.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "testdata", + "version": "0.1.0", + "dependencies": { + "@azure-tools/typespec-autorest": "0.39.2", + "@azure-tools/typespec-azure-core": "0.39.1", + "@typespec/compiler": "~0.53.1", + "@typespec/openapi3": "~0.53.1" + } + }, + "node_modules/@azure-tools/typespec-autorest": { + "version": "0.39.2", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-autorest/-/typespec-autorest-0.39.2.tgz", + "integrity": "sha512-sdYbYKv6uIktMqX573buyMoLiJMTCwk17DN/CeX0NPtmSx1SXLPh9stQFg2H/IMgVS8VmTlVeCYoSKR7krjsGg==", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@azure-tools/typespec-azure-core": "~0.39.1", + "@azure-tools/typespec-client-generator-core": "~0.39.0", + "@typespec/compiler": "~0.53.1", + "@typespec/http": "~0.53.0", + "@typespec/openapi": "~0.53.0", + "@typespec/rest": "~0.53.0", + "@typespec/versioning": "~0.53.0" + } + }, + "node_modules/@azure-tools/typespec-azure-core": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-azure-core/-/typespec-azure-core-0.39.1.tgz", + "integrity": "sha512-b1cN1HXTcEiKIRpk2EatFK/C4NReDaW2h4N3V4C5dxGeeLAnTa1jsQ6lwobH6Zo39CdrjazNXiSbcEq1UZ7kPw==", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.53.1", + "@typespec/http": "~0.53.0", + "@typespec/rest": "~0.53.0" + } + }, + "node_modules/@azure-tools/typespec-client-generator-core": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@azure-tools/typespec-client-generator-core/-/typespec-client-generator-core-0.39.1.tgz", + "integrity": "sha512-EV3N6IN1i/hXGqYKNfXx6+2QAyZnG4IpC9RUk6fqwSQDWX7HtMcfdXqlOaK3Rz2H6BUAc9OnH+Trq/uJCl/RgA==", + "peer": true, + "dependencies": { + "change-case": "~5.3.0", + "pluralize": "^8.0.0" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.53.1", + "@typespec/http": "~0.53.0", + "@typespec/rest": "~0.53.0", + "@typespec/versioning": "~0.53.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.2.1.tgz", + "integrity": "sha512-255V7MMIKw6aQ43Wbqp9HZ+VHn6acddERTLiiLnlcPLU9PdTq9Aijl12oklAgUEblLWye+vHLzmqBx6f2TGcZw==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typespec/compiler": { + "version": "0.53.1", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-0.53.1.tgz", + "integrity": "sha512-qneMDvZsLaL8+3PXzwXMAqgE4YtkUPPBg4oXrbreYa5NTccuvgVaO4cfya/SzG4WePUnmDTbbrP5aWd+VzYwYA==", + "dependencies": { + "@babel/code-frame": "~7.23.5", + "ajv": "~8.12.0", + "change-case": "~5.3.0", + "globby": "~14.0.0", + "mustache": "~4.2.0", + "picocolors": "~1.0.0", + "prettier": "~3.1.1", + "prompts": "~2.4.2", + "semver": "^7.5.4", + "vscode-languageserver": "~9.0.0", + "vscode-languageserver-textdocument": "~1.0.8", + "yaml": "~2.3.4", + "yargs": "~17.7.2" + }, + "bin": { + "tsp": "cmd/tsp.js", + "tsp-server": "cmd/tsp-server.js" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@typespec/http": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-0.53.0.tgz", + "integrity": "sha512-Hdwbxr6KgzmJdULbbcwWaSSrWlduuMuEVUVdlytxyo9K+aoUCcPl0thR5Ez2VRh02/IJl3xG4n5wXgOwWb3amA==", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.53.0" + } + }, + "node_modules/@typespec/openapi": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-0.53.0.tgz", + "integrity": "sha512-FRHb6Wi4Yf1HGm3EnhhXZ0Bw+EIPam6ptxRy7NDRxyMnzHsOphGcv8mDIZk6MPSy8xPasbFNwaRC1TXpxVhQBw==", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.53.0", + "@typespec/http": "~0.53.0" + } + }, + "node_modules/@typespec/openapi3": { + "version": "0.53.2", + "resolved": "https://registry.npmjs.org/@typespec/openapi3/-/openapi3-0.53.2.tgz", + "integrity": "sha512-8uwU3iJbt+WN3WlT9VzC7DN8rzB727zr8BMwZ81XN1/sX8dOJB49F5UiK0L+ychvx15RZ96CvYPCFmmnsOeyCQ==", + "dependencies": { + "yaml": "~2.3.4" + }, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.53.1", + "@typespec/http": "~0.53.0", + "@typespec/openapi": "~0.53.0", + "@typespec/versioning": "~0.53.0" + } + }, + "node_modules/@typespec/rest": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.53.0.tgz", + "integrity": "sha512-aA75Ol2pRvUjtRqQvFHmFG52pkeif3m+tboLAT00AekTxOPZ3rqQmlE12ne4QF8KjgHA6denqH4f/XyDoRJOJQ==", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.53.0", + "@typespec/http": "~0.53.0" + } + }, + "node_modules/@typespec/versioning": { + "version": "0.53.0", + "resolved": "https://registry.npmjs.org/@typespec/versioning/-/versioning-0.53.0.tgz", + "integrity": "sha512-nrrLXCWPDrrClAfpCMzQ3YPTbKQmjPC3LSeMjq+wPiMq+1PW95ulOGD4QiCBop+4wKhMCJHnqqSzVauT1LjdvQ==", + "peer": true, + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "~0.53.0" + } + }, + "node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/change-case": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.3.0.tgz", + "integrity": "sha512-Eykca0fGS/xYlx2fG5NqnGSnsWauhSGiSXYhB1kO6E909GUfo8S54u4UZNS7lMJmgZumZ2SUpWaoLgAcfQRICg==" + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "engines": { + "node": ">=6" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "peer": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/prettier": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.1.tgz", + "integrity": "sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==" + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/vscode-jsonrpc": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.2.0.tgz", + "integrity": "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-9.0.1.tgz", + "integrity": "sha512-woByF3PDpkHFUreUa7Hos7+pUWdeWMXRd26+ZX2A8cFx6v/JPTtd4/uN0/jB6XQHYaOlHbio03NTHCqrgG5n7g==", + "dependencies": { + "vscode-languageserver-protocol": "3.17.5" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.5.tgz", + "integrity": "sha512-mb1bvRJN8SVznADSGWM9u/b07H7Ecg0I3OgXDuLdn307rl/J3A9YD6/eYOssqhecL27hK1IPZAsaqh00i/Jljg==", + "dependencies": { + "vscode-jsonrpc": "8.2.0", + "vscode-languageserver-types": "3.17.5" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.8.tgz", + "integrity": "sha512-1bonkGqQs5/fxGT5UchTgjGVnfysL0O8v1AYMBjqTbWQTFn721zaPGDYFkOKtfDgFiSgXM3KwaG3FMGfW4Ed9Q==" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.17.5", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.5.tgz", + "integrity": "sha512-Ld1VelNuX9pdF39h2Hgaeb5hEZM2Z3jUrrMgWQAu82jMtZp7p3vJT3BzToKtZI7NgQssZje5o0zryOrhQvzQAg==" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "engines": { + "node": ">= 14" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + } + } +} diff --git a/sdk/ai/azopenaiassistants/testdata/package.json b/sdk/ai/azopenaiassistants/testdata/package.json new file mode 100644 index 000000000000..7ac3a189b958 --- /dev/null +++ b/sdk/ai/azopenaiassistants/testdata/package.json @@ -0,0 +1,16 @@ +{ + "name": "testdata", + "version": "0.1.0", + "type": "module", + "scripts": { + "pull": "pwsh ../../../../eng/common/scripts/TypeSpec-Project-Sync.ps1 -ProjectDirectory . && rm ./TempTypeSpecFiles/OpenAI.Assistants/tspconfig.yaml", + "build": "tsp compile ./TempTypeSpecFiles/OpenAI.Assistants" + }, + "dependencies": { + "@azure-tools/typespec-autorest": "0.39.2", + "@azure-tools/typespec-azure-core": "0.39.1", + "@typespec/compiler": "~0.53.1", + "@typespec/openapi3": "~0.53.1" + }, + "private": true +} diff --git a/sdk/ai/azopenaiassistants/testdata/tsp-location.yaml b/sdk/ai/azopenaiassistants/testdata/tsp-location.yaml new file mode 100644 index 000000000000..2f57d1a44d53 --- /dev/null +++ b/sdk/ai/azopenaiassistants/testdata/tsp-location.yaml @@ -0,0 +1,4 @@ +#location: https://raw.githubusercontent.com/Azure/azure-rest-api-specs/cacb3dc095486d8691c47dea944fc9ed0f4d0e32/specification/ai/OpenAI.Assistants/client.tsp +directory: specification/ai/OpenAI.Assistants +commit: bcecb9990214471ee523e643da76a3a7c4170d2f +repo: Azure/azure-rest-api-specs diff --git a/sdk/ai/azopenaiassistants/testdata/tspconfig.yaml b/sdk/ai/azopenaiassistants/testdata/tspconfig.yaml new file mode 100644 index 000000000000..c65b2dd96987 --- /dev/null +++ b/sdk/ai/azopenaiassistants/testdata/tspconfig.yaml @@ -0,0 +1,11 @@ +parameters: + "service-dir": + default: "sdk/azopenaiassistants" + "dependencies": + default: "" +emit: + - "@azure-tools/typespec-autorest" +options: + "@azure-tools/typespec-autorest": + emitter-output-dir: "{project-root}/generated" + output-file: "openapi.json" diff --git a/sdk/ai/azopenaiassistants/time_rfc3339.go b/sdk/ai/azopenaiassistants/time_rfc3339.go new file mode 100644 index 000000000000..7f5f03029031 --- /dev/null +++ b/sdk/ai/azopenaiassistants/time_rfc3339.go @@ -0,0 +1,111 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +import ( + "encoding/json" + "fmt" + "reflect" + "regexp" + "strings" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +// Azure reports time in UTC but it doesn't include the 'Z' time zone suffix in some cases. +var tzOffsetRegex = regexp.MustCompile(`(?:Z|z|\+|-)(?:\d+:\d+)*"*$`) + +const ( + utcDateTime = "2006-01-02T15:04:05.999999999" + utcDateTimeJSON = `"` + utcDateTime + `"` + utcDateTimeNoT = "2006-01-02 15:04:05.999999999" + utcDateTimeJSONNoT = `"` + utcDateTimeNoT + `"` + dateTimeNoT = `2006-01-02 15:04:05.999999999Z07:00` + dateTimeJSON = `"` + time.RFC3339Nano + `"` + dateTimeJSONNoT = `"` + dateTimeNoT + `"` +) + +type dateTimeRFC3339 time.Time + +func (t dateTimeRFC3339) MarshalJSON() ([]byte, error) { + tt := time.Time(t) + return tt.MarshalJSON() +} + +func (t dateTimeRFC3339) MarshalText() ([]byte, error) { + tt := time.Time(t) + return tt.MarshalText() +} + +func (t *dateTimeRFC3339) UnmarshalJSON(data []byte) error { + tzOffset := tzOffsetRegex.Match(data) + hasT := strings.Contains(string(data), "T") || strings.Contains(string(data), "t") + var layout string + if tzOffset && hasT { + layout = dateTimeJSON + } else if tzOffset { + layout = dateTimeJSONNoT + } else if hasT { + layout = utcDateTimeJSON + } else { + layout = utcDateTimeJSONNoT + } + return t.Parse(layout, string(data)) +} + +func (t *dateTimeRFC3339) UnmarshalText(data []byte) error { + tzOffset := tzOffsetRegex.Match(data) + hasT := strings.Contains(string(data), "T") || strings.Contains(string(data), "t") + var layout string + if tzOffset && hasT { + layout = time.RFC3339Nano + } else if tzOffset { + layout = dateTimeNoT + } else if hasT { + layout = utcDateTime + } else { + layout = utcDateTimeNoT + } + return t.Parse(layout, string(data)) +} + +func (t *dateTimeRFC3339) Parse(layout, value string) error { + p, err := time.Parse(layout, strings.ToUpper(value)) + *t = dateTimeRFC3339(p) + return err +} + +func (t dateTimeRFC3339) String() string { + return time.Time(t).Format(time.RFC3339Nano) +} + +func populateDateTimeRFC3339(m map[string]any, k string, t *time.Time) { + if t == nil { + return + } else if azcore.IsNullValue(t) { + m[k] = nil + return + } else if reflect.ValueOf(t).IsNil() { + return + } + m[k] = (*dateTimeRFC3339)(t) +} + +func unpopulateDateTimeRFC3339(data json.RawMessage, fn string, t **time.Time) error { + if data == nil || string(data) == "null" { + return nil + } + var aux dateTimeRFC3339 + if err := json.Unmarshal(data, &aux); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + *t = (*time.Time)(&aux) + return nil +} diff --git a/sdk/ai/azopenaiassistants/time_unix.go b/sdk/ai/azopenaiassistants/time_unix.go new file mode 100644 index 000000000000..910c016ba013 --- /dev/null +++ b/sdk/ai/azopenaiassistants/time_unix.go @@ -0,0 +1,61 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. +// Code generated by Microsoft (R) AutoRest Code Generator. DO NOT EDIT. +// Changes may cause incorrect behavior and will be lost if the code is regenerated. + +package azopenaiassistants + +import ( + "encoding/json" + "fmt" + "reflect" + "time" + + "github.com/Azure/azure-sdk-for-go/sdk/azcore" +) + +type timeUnix time.Time + +func (t timeUnix) MarshalJSON() ([]byte, error) { + return json.Marshal(time.Time(t).Unix()) +} + +func (t *timeUnix) UnmarshalJSON(data []byte) error { + var seconds int64 + if err := json.Unmarshal(data, &seconds); err != nil { + return err + } + *t = timeUnix(time.Unix(seconds, 0)) + return nil +} + +func (t timeUnix) String() string { + return fmt.Sprintf("%d", time.Time(t).Unix()) +} + +func populateTimeUnix(m map[string]any, k string, t *time.Time) { + if t == nil { + return + } else if azcore.IsNullValue(t) { + m[k] = nil + return + } else if reflect.ValueOf(t).IsNil() { + return + } + m[k] = (*timeUnix)(t) +} + +func unpopulateTimeUnix(data json.RawMessage, fn string, t **time.Time) error { + if data == nil || string(data) == "null" { + return nil + } + var aux timeUnix + if err := json.Unmarshal(data, &aux); err != nil { + return fmt.Errorf("struct field %s: %v", fn, err) + } + *t = (*time.Time)(&aux) + return nil +} diff --git a/sdk/ai/azopenaiassistants/version.go b/sdk/ai/azopenaiassistants/version.go new file mode 100644 index 000000000000..ed13d93e1c0b --- /dev/null +++ b/sdk/ai/azopenaiassistants/version.go @@ -0,0 +1,11 @@ +//go:build go1.18 +// +build go1.18 + +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +package azopenaiassistants + +const ( + version = "v0.1.0" +)