diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 1aa883d..8587ff4 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -5,19 +5,18 @@ RUN apt-get update && apt-get install -y \
libxkbcommon0 \
ca-certificates \
git \
- golang \
unzip \
libc++1 \
vim \
+ curl \
+ procps \
&& apt-get clean autoclean
+RUN curl -OL https://go.dev/dl/go1.24.0.linux-amd64.tar.gz && \
+ tar -C /usr/local -xzvf go1.24.0.linux-amd64.tar.gz && \
+ rm go1.24.0.linux-amd64.tar.gz
+ENV PATH="$PATH:/usr/local/go/bin"
+
# Ensure UTF-8 encoding
ENV LANG=C.UTF-8
ENV LC_ALL=C.UTF-8
-
-ENV GOPATH=/go
-ENV PATH=$GOPATH/bin:$PATH
-
-WORKDIR /workspace
-
-COPY . /workspace
diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml
deleted file mode 100644
index d15f4f6..0000000
--- a/.github/workflows/create-releases.yml
+++ /dev/null
@@ -1,28 +0,0 @@
-name: Create releases
-on:
- schedule:
- - cron: '0 5 * * *' # every day at 5am UTC
- push:
- branches:
- - main
-
-jobs:
- release:
- name: release
- if: github.ref == 'refs/heads/main' && github.repository == 'openlayer-ai/openlayer-go'
- runs-on: ubuntu-latest
-
- steps:
- - uses: actions/checkout@v4
-
- - uses: stainless-api/trigger-release-please@v1
- id: release
- with:
- repo: ${{ github.event.repository.full_name }}
- stainless-api-key: ${{ secrets.STAINLESS_API_KEY }}
-
- - name: Generate godocs
- if: ${{ steps.release.outputs.releases_created }}
- run: |
- version=$(jq -r '. | to_entries[0] | .value' .release-please-manifest.json)
- curl -X POST https://pkg.go.dev/fetch/github.com/openlayer-ai/openlayer-go@v${version}
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index 000572e..b069996 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.1.0-alpha.13"
+ ".": "0.1.0-alpha.14"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index dd47305..c254947 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1 +1 @@
-configured_endpoints: 14
+configured_endpoints: 15
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 454a964..bb0ec58 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,39 @@
# Changelog
+## 0.1.0-alpha.14 (2025-03-13)
+
+Full Changelog: [v0.1.0-alpha.13...v0.1.0-alpha.14](https://github.com/openlayer-ai/openlayer-go/compare/v0.1.0-alpha.13...v0.1.0-alpha.14)
+
+### Features
+
+* **api:** add endpoint to retrieve commit by id ([#64](https://github.com/openlayer-ai/openlayer-go/issues/64)) ([201cb4a](https://github.com/openlayer-ai/openlayer-go/commit/201cb4acd0e572cecb46ffdc29979c38a52846fb))
+* **api:** api update ([1d5c8e7](https://github.com/openlayer-ai/openlayer-go/commit/1d5c8e7f9a98ab806517fbd7c2ac8c6ac456f04d))
+* **client:** send `X-Stainless-Timeout` header ([d9948ef](https://github.com/openlayer-ai/openlayer-go/commit/d9948ef4b8b56ed71ddd2ea0f4519bf40dc5d52f))
+
+
+### Bug Fixes
+
+* **client:** don't truncate manually specified filenames ([f7b96d9](https://github.com/openlayer-ai/openlayer-go/commit/f7b96d9ebe96937df548fe0797fbbaf8ba77109a))
+* do not call path.Base on ContentType ([0b98d8e](https://github.com/openlayer-ai/openlayer-go/commit/0b98d8e38cb8716cc61ee62f9aa4b58250a4b581))
+* fix early cancel when RequestTimeout is provided for streaming requests ([f0c9a39](https://github.com/openlayer-ai/openlayer-go/commit/f0c9a39e93d5aab9a2f78b95f1a6ee0aa27632ca))
+* fix interface implementation stub names for unions ([0d8c74f](https://github.com/openlayer-ai/openlayer-go/commit/0d8c74f4d02b5d154357d98e892ac074470b474b))
+* fix unicode encoding for json ([cdaee21](https://github.com/openlayer-ai/openlayer-go/commit/cdaee2125cb3c27f1a94cefc70d87ad5e12b79cc))
+
+
+### Chores
+
+* add UnionUnmarshaler for responses that are interfaces ([3295c9b](https://github.com/openlayer-ai/openlayer-go/commit/3295c9bcc892bf7db4f1068120be3a86b86b1281))
+* **internal:** codegen related update ([57b756f](https://github.com/openlayer-ai/openlayer-go/commit/57b756f1e31665115bc2cac4d7527f21965376ad))
+* **internal:** codegen related update ([c2a18b7](https://github.com/openlayer-ai/openlayer-go/commit/c2a18b7d8ebe2df5f23428be410172a0dbd330cd))
+* **internal:** codegen related update ([5582642](https://github.com/openlayer-ai/openlayer-go/commit/5582642f1d2b958566a842f4c9663baea39563cc))
+* **internal:** fix devcontainers setup ([1d42cd7](https://github.com/openlayer-ai/openlayer-go/commit/1d42cd7adbc487450809a3da28cdb47cc11da3db))
+* refactor client tests ([d2732fe](https://github.com/openlayer-ai/openlayer-go/commit/d2732fee321e2f829eafa4374c0c093d6e378f72))
+
+
+### Documentation
+
+* document raw responses ([1c66d2a](https://github.com/openlayer-ai/openlayer-go/commit/1c66d2a1e698e42799d142ff57ad1b2a51630b98))
+
## 0.1.0-alpha.13 (2025-01-02)
Full Changelog: [v0.1.0-alpha.12...v0.1.0-alpha.13](https://github.com/openlayer-ai/openlayer-go/compare/v0.1.0-alpha.12...v0.1.0-alpha.13)
diff --git a/README.md b/README.md
index a94ee33..9146ee8 100644
--- a/README.md
+++ b/README.md
@@ -24,7 +24,7 @@ Or to pin the version:
```sh
-go get -u 'github.com/openlayer-ai/openlayer-go@v0.1.0-alpha.13'
+go get -u 'github.com/openlayer-ai/openlayer-go@v0.1.0-alpha.14'
```
@@ -66,9 +66,9 @@ func main() {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
@@ -207,9 +207,9 @@ _, err := client.InferencePipelines.Data.Stream(
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
@@ -251,9 +251,9 @@ client.InferencePipelines.Data.Stream(
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
// This sets the per-retry timeout
@@ -303,15 +303,53 @@ client.InferencePipelines.Data.Stream(
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
option.WithMaxRetries(5),
)
```
+### Accessing raw response data (e.g. response headers)
+
+You can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when
+you need to examine response headers, status codes, or other details.
+
+```go
+// Create a variable to store the HTTP response
+var response *http.Response
+response, err := client.InferencePipelines.Data.Stream(
+ context.TODO(),
+ "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
+ openlayer.InferencePipelineDataStreamParams{
+ Config: openlayer.F[openlayer.InferencePipelineDataStreamParamsConfigUnion](openlayer.InferencePipelineDataStreamParamsConfigLlmData{
+ InputVariableNames: openlayer.F([]string{"user_query"}),
+ OutputColumnName: openlayer.F("output"),
+ NumOfTokenColumnName: openlayer.F("tokens"),
+ CostColumnName: openlayer.F("cost"),
+ TimestampColumnName: openlayer.F("timestamp"),
+ }),
+ Rows: openlayer.F([]map[string]interface{}{{
+ "user_query": "what is the meaning of life?",
+ "output": "42",
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
+ }}),
+ },
+ option.WithResponseInto(&response),
+)
+if err != nil {
+ // handle error
+}
+fmt.Printf("%+v\n", response)
+
+fmt.Printf("Status Code: %d\n", response.StatusCode)
+fmt.Printf("Headers: %+#v\n", response.Header)
+```
+
### Making custom/undocumented requests
This library is typed for convenient access to the documented API. If you need to access undocumented
@@ -402,7 +440,7 @@ middleware has been applied.
This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:
-1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_.
+1. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_
2. Changes that we do not expect to impact the vast majority of users in practice.
We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.
diff --git a/api.md b/api.md
index 1e30d91..bf0898d 100644
--- a/api.md
+++ b/api.md
@@ -36,6 +36,14 @@ Methods:
# Commits
+Response Types:
+
+- openlayer.CommitGetResponse
+
+Methods:
+
+- client.Commits.Get(ctx context.Context, projectVersionID string) (openlayer.CommitGetResponse, error)
+
## TestResults
Response Types:
diff --git a/client_test.go b/client_test.go
index 4370936..e498ab9 100644
--- a/client_test.go
+++ b/client_test.go
@@ -51,9 +51,9 @@ func TestUserAgentHeader(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
@@ -79,7 +79,7 @@ func TestRetryAfter(t *testing.T) {
},
}),
)
- res, err := client.InferencePipelines.Data.Stream(
+ _, err := client.InferencePipelines.Data.Stream(
context.Background(),
"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
openlayer.InferencePipelineDataStreamParams{
@@ -93,14 +93,14 @@ func TestRetryAfter(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
- if err == nil || res != nil {
- t.Error("Expected there to be a cancel error and for the response to be nil")
+ if err == nil {
+ t.Error("Expected there to be a cancel error")
}
attempts := len(retryCountHeaders)
@@ -132,7 +132,7 @@ func TestDeleteRetryCountHeader(t *testing.T) {
}),
option.WithHeaderDel("X-Stainless-Retry-Count"),
)
- res, err := client.InferencePipelines.Data.Stream(
+ _, err := client.InferencePipelines.Data.Stream(
context.Background(),
"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
openlayer.InferencePipelineDataStreamParams{
@@ -146,14 +146,14 @@ func TestDeleteRetryCountHeader(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
- if err == nil || res != nil {
- t.Error("Expected there to be a cancel error and for the response to be nil")
+ if err == nil {
+ t.Error("Expected there to be a cancel error")
}
expectedRetryCountHeaders := []string{"", "", ""}
@@ -180,7 +180,7 @@ func TestOverwriteRetryCountHeader(t *testing.T) {
}),
option.WithHeader("X-Stainless-Retry-Count", "42"),
)
- res, err := client.InferencePipelines.Data.Stream(
+ _, err := client.InferencePipelines.Data.Stream(
context.Background(),
"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
openlayer.InferencePipelineDataStreamParams{
@@ -194,14 +194,14 @@ func TestOverwriteRetryCountHeader(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
- if err == nil || res != nil {
- t.Error("Expected there to be a cancel error and for the response to be nil")
+ if err == nil {
+ t.Error("Expected there to be a cancel error")
}
expectedRetryCountHeaders := []string{"42", "42", "42"}
@@ -227,7 +227,7 @@ func TestRetryAfterMs(t *testing.T) {
},
}),
)
- res, err := client.InferencePipelines.Data.Stream(
+ _, err := client.InferencePipelines.Data.Stream(
context.Background(),
"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
openlayer.InferencePipelineDataStreamParams{
@@ -241,14 +241,14 @@ func TestRetryAfterMs(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
- if err == nil || res != nil {
- t.Error("Expected there to be a cancel error and for the response to be nil")
+ if err == nil {
+ t.Error("Expected there to be a cancel error")
}
if want := 3; attempts != want {
t.Errorf("Expected %d attempts, got %d", want, attempts)
@@ -268,7 +268,7 @@ func TestContextCancel(t *testing.T) {
)
cancelCtx, cancel := context.WithCancel(context.Background())
cancel()
- res, err := client.InferencePipelines.Data.Stream(
+ _, err := client.InferencePipelines.Data.Stream(
cancelCtx,
"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
openlayer.InferencePipelineDataStreamParams{
@@ -282,14 +282,14 @@ func TestContextCancel(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
- if err == nil || res != nil {
- t.Error("Expected there to be a cancel error and for the response to be nil")
+ if err == nil {
+ t.Error("Expected there to be a cancel error")
}
}
@@ -306,7 +306,7 @@ func TestContextCancelDelay(t *testing.T) {
)
cancelCtx, cancel := context.WithTimeout(context.Background(), 2*time.Millisecond)
defer cancel()
- res, err := client.InferencePipelines.Data.Stream(
+ _, err := client.InferencePipelines.Data.Stream(
cancelCtx,
"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
openlayer.InferencePipelineDataStreamParams{
@@ -320,14 +320,14 @@ func TestContextCancelDelay(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
- if err == nil || res != nil {
- t.Error("expected there to be a cancel error and for the response to be nil")
+ if err == nil {
+ t.Error("expected there to be a cancel error")
}
}
@@ -350,7 +350,7 @@ func TestContextDeadline(t *testing.T) {
},
}),
)
- res, err := client.InferencePipelines.Data.Stream(
+ _, err := client.InferencePipelines.Data.Stream(
deadlineCtx,
"182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e",
openlayer.InferencePipelineDataStreamParams{
@@ -364,14 +364,14 @@ func TestContextDeadline(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)
- if err == nil || res != nil {
- t.Error("expected there to be a deadline error and for the response to be nil")
+ if err == nil {
+ t.Error("expected there to be a deadline error")
}
close(testDone)
}()
diff --git a/commit.go b/commit.go
index 651371a..9bcda00 100644
--- a/commit.go
+++ b/commit.go
@@ -3,6 +3,14 @@
package openlayer
import (
+ "context"
+ "errors"
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/openlayer-ai/openlayer-go/internal/apijson"
+ "github.com/openlayer-ai/openlayer-go/internal/requestconfig"
"github.com/openlayer-ai/openlayer-go/option"
)
@@ -26,3 +34,180 @@ func NewCommitService(opts ...option.RequestOption) (r *CommitService) {
r.TestResults = NewCommitTestResultService(opts...)
return
}
+
+// Retrieve a project version (commit) by its id.
+func (r *CommitService) Get(ctx context.Context, projectVersionID string, opts ...option.RequestOption) (res *CommitGetResponse, err error) {
+ opts = append(r.Options[:], opts...)
+ if projectVersionID == "" {
+ err = errors.New("missing required projectVersionId parameter")
+ return
+ }
+ path := fmt.Sprintf("versions/%s", projectVersionID)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ return
+}
+
+type CommitGetResponse struct {
+ // The project version (commit) id.
+ ID string `json:"id,required" format:"uuid"`
+ // The details of a commit (project version).
+ Commit CommitGetResponseCommit `json:"commit,required"`
+ // The commit archive date.
+ DateArchived time.Time `json:"dateArchived,required,nullable" format:"date-time"`
+ // The project version (commit) creation date.
+ DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
+ // The number of tests that are failing for the commit.
+ FailingGoalCount int64 `json:"failingGoalCount,required"`
+ // The model id.
+ MlModelID string `json:"mlModelId,required,nullable" format:"uuid"`
+ // The number of tests that are passing for the commit.
+ PassingGoalCount int64 `json:"passingGoalCount,required"`
+ // The project id.
+ ProjectID string `json:"projectId,required" format:"uuid"`
+ // The commit status. Initially, the commit is `queued`, then, it switches to
+ // `running`. Finally, it can be `paused`, `failed`, or `completed`.
+ Status CommitGetResponseStatus `json:"status,required"`
+ // The commit status message.
+ StatusMessage string `json:"statusMessage,required,nullable"`
+ // The total number of tests for the commit.
+ TotalGoalCount int64 `json:"totalGoalCount,required"`
+ // The training dataset id.
+ TrainingDatasetID string `json:"trainingDatasetId,required,nullable" format:"uuid"`
+ // The validation dataset id.
+ ValidationDatasetID string `json:"validationDatasetId,required,nullable" format:"uuid"`
+ // Whether the commit is archived.
+ Archived bool `json:"archived,nullable"`
+ // The deployment status associated with the commit's model.
+ DeploymentStatus string `json:"deploymentStatus"`
+ Links CommitGetResponseLinks `json:"links"`
+ JSON commitGetResponseJSON `json:"-"`
+}
+
+// commitGetResponseJSON contains the JSON metadata for the struct
+// [CommitGetResponse]
+type commitGetResponseJSON struct {
+ ID apijson.Field
+ Commit apijson.Field
+ DateArchived apijson.Field
+ DateCreated apijson.Field
+ FailingGoalCount apijson.Field
+ MlModelID apijson.Field
+ PassingGoalCount apijson.Field
+ ProjectID apijson.Field
+ Status apijson.Field
+ StatusMessage apijson.Field
+ TotalGoalCount apijson.Field
+ TrainingDatasetID apijson.Field
+ ValidationDatasetID apijson.Field
+ Archived apijson.Field
+ DeploymentStatus apijson.Field
+ Links apijson.Field
+ raw string
+ ExtraFields map[string]apijson.Field
+}
+
+func (r *CommitGetResponse) UnmarshalJSON(data []byte) (err error) {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func (r commitGetResponseJSON) RawJSON() string {
+ return r.raw
+}
+
+// The details of a commit (project version).
+type CommitGetResponseCommit struct {
+ // The commit id.
+ ID string `json:"id,required" format:"uuid"`
+ // The author id of the commit.
+ AuthorID string `json:"authorId,required" format:"uuid"`
+ // The size of the commit bundle in bytes.
+ FileSize int64 `json:"fileSize,required,nullable"`
+ // The commit message.
+ Message string `json:"message,required"`
+ // The model id.
+ MlModelID string `json:"mlModelId,required,nullable" format:"uuid"`
+ // The storage URI where the commit bundle is stored.
+ StorageUri string `json:"storageUri,required"`
+ // The training dataset id.
+ TrainingDatasetID string `json:"trainingDatasetId,required,nullable" format:"uuid"`
+ // The validation dataset id.
+ ValidationDatasetID string `json:"validationDatasetId,required,nullable" format:"uuid"`
+ // The commit creation date.
+ DateCreated time.Time `json:"dateCreated" format:"date-time"`
+ // The ref of the corresponding git commit.
+ GitCommitRef string `json:"gitCommitRef"`
+ // The SHA of the corresponding git commit.
+ GitCommitSha int64 `json:"gitCommitSha"`
+ // The URL of the corresponding git commit.
+ GitCommitURL string `json:"gitCommitUrl"`
+ JSON commitGetResponseCommitJSON `json:"-"`
+}
+
+// commitGetResponseCommitJSON contains the JSON metadata for the struct
+// [CommitGetResponseCommit]
+type commitGetResponseCommitJSON struct {
+ ID apijson.Field
+ AuthorID apijson.Field
+ FileSize apijson.Field
+ Message apijson.Field
+ MlModelID apijson.Field
+ StorageUri apijson.Field
+ TrainingDatasetID apijson.Field
+ ValidationDatasetID apijson.Field
+ DateCreated apijson.Field
+ GitCommitRef apijson.Field
+ GitCommitSha apijson.Field
+ GitCommitURL apijson.Field
+ raw string
+ ExtraFields map[string]apijson.Field
+}
+
+func (r *CommitGetResponseCommit) UnmarshalJSON(data []byte) (err error) {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func (r commitGetResponseCommitJSON) RawJSON() string {
+ return r.raw
+}
+
+// The commit status. Initially, the commit is `queued`, then, it switches to
+// `running`. Finally, it can be `paused`, `failed`, or `completed`.
+type CommitGetResponseStatus string
+
+const (
+ CommitGetResponseStatusQueued CommitGetResponseStatus = "queued"
+ CommitGetResponseStatusRunning CommitGetResponseStatus = "running"
+ CommitGetResponseStatusPaused CommitGetResponseStatus = "paused"
+ CommitGetResponseStatusFailed CommitGetResponseStatus = "failed"
+ CommitGetResponseStatusCompleted CommitGetResponseStatus = "completed"
+ CommitGetResponseStatusUnknown CommitGetResponseStatus = "unknown"
+)
+
+func (r CommitGetResponseStatus) IsKnown() bool {
+ switch r {
+ case CommitGetResponseStatusQueued, CommitGetResponseStatusRunning, CommitGetResponseStatusPaused, CommitGetResponseStatusFailed, CommitGetResponseStatusCompleted, CommitGetResponseStatusUnknown:
+ return true
+ }
+ return false
+}
+
+type CommitGetResponseLinks struct {
+ App string `json:"app,required"`
+ JSON commitGetResponseLinksJSON `json:"-"`
+}
+
+// commitGetResponseLinksJSON contains the JSON metadata for the struct
+// [CommitGetResponseLinks]
+type commitGetResponseLinksJSON struct {
+ App apijson.Field
+ raw string
+ ExtraFields map[string]apijson.Field
+}
+
+func (r *CommitGetResponseLinks) UnmarshalJSON(data []byte) (err error) {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+func (r commitGetResponseLinksJSON) RawJSON() string {
+ return r.raw
+}
diff --git a/commit_test.go b/commit_test.go
new file mode 100644
index 0000000..15bb08b
--- /dev/null
+++ b/commit_test.go
@@ -0,0 +1,36 @@
+// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
+
+package openlayer_test
+
+import (
+ "context"
+ "errors"
+ "os"
+ "testing"
+
+ "github.com/openlayer-ai/openlayer-go"
+ "github.com/openlayer-ai/openlayer-go/internal/testutil"
+ "github.com/openlayer-ai/openlayer-go/option"
+)
+
+func TestCommitGet(t *testing.T) {
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := openlayer.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ _, err := client.Commits.Get(context.TODO(), "182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e")
+ if err != nil {
+ var apierr *openlayer.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
diff --git a/field.go b/field.go
index 388bfca..a55d709 100644
--- a/field.go
+++ b/field.go
@@ -46,5 +46,5 @@ type file struct {
contentType string
}
-func (f *file) Name() string { return f.name }
func (f *file) ContentType() string { return f.contentType }
+func (f *file) Filename() string { return f.name }
diff --git a/inferencepipeline.go b/inferencepipeline.go
index 38c6671..76d85c1 100644
--- a/inferencepipeline.go
+++ b/inferencepipeline.go
@@ -357,22 +357,34 @@ func (r inferencePipelineGetResponseProjectGitRepoJSON) RawJSON() string {
}
type InferencePipelineGetResponseWorkspace struct {
- ID string `json:"id,required" format:"uuid"`
- CreatorID string `json:"creatorId,required,nullable" format:"uuid"`
- DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
- DateUpdated time.Time `json:"dateUpdated,required" format:"date-time"`
- InviteCount int64 `json:"inviteCount,required"`
- MemberCount int64 `json:"memberCount,required"`
- Name string `json:"name,required"`
- PeriodEndDate time.Time `json:"periodEndDate,required,nullable" format:"date-time"`
- PeriodStartDate time.Time `json:"periodStartDate,required,nullable" format:"date-time"`
- ProjectCount int64 `json:"projectCount,required"`
- Slug string `json:"slug,required"`
- Status InferencePipelineGetResponseWorkspaceStatus `json:"status,required"`
- MonthlyUsage []InferencePipelineGetResponseWorkspaceMonthlyUsage `json:"monthlyUsage"`
- SAMLOnlyAccess bool `json:"samlOnlyAccess"`
- WildcardDomains []string `json:"wildcardDomains"`
- JSON inferencePipelineGetResponseWorkspaceJSON `json:"-"`
+ // The workspace id.
+ ID string `json:"id,required" format:"uuid"`
+ // The workspace creator id.
+ CreatorID string `json:"creatorId,required,nullable" format:"uuid"`
+ // The workspace creation date.
+ DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
+ // The workspace last updated date.
+ DateUpdated time.Time `json:"dateUpdated,required" format:"date-time"`
+ // The number of invites in the workspace.
+ InviteCount int64 `json:"inviteCount,required"`
+ // The number of members in the workspace.
+ MemberCount int64 `json:"memberCount,required"`
+ // The workspace name.
+ Name string `json:"name,required"`
+ // The end date of the current billing period.
+ PeriodEndDate time.Time `json:"periodEndDate,required,nullable" format:"date-time"`
+ // The start date of the current billing period.
+ PeriodStartDate time.Time `json:"periodStartDate,required,nullable" format:"date-time"`
+ // The number of projects in the workspace.
+ ProjectCount int64 `json:"projectCount,required"`
+ // The workspace slug.
+ Slug string `json:"slug,required"`
+ Status InferencePipelineGetResponseWorkspaceStatus `json:"status,required"`
+ MonthlyUsage []InferencePipelineGetResponseWorkspaceMonthlyUsage `json:"monthlyUsage"`
+ // Whether the workspace only allows SAML authentication.
+ SAMLOnlyAccess bool `json:"samlOnlyAccess"`
+ WildcardDomains []string `json:"wildcardDomains"`
+ JSON inferencePipelineGetResponseWorkspaceJSON `json:"-"`
}
// inferencePipelineGetResponseWorkspaceJSON contains the JSON metadata for the
@@ -729,22 +741,34 @@ func (r inferencePipelineUpdateResponseProjectGitRepoJSON) RawJSON() string {
}
type InferencePipelineUpdateResponseWorkspace struct {
- ID string `json:"id,required" format:"uuid"`
- CreatorID string `json:"creatorId,required,nullable" format:"uuid"`
- DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
- DateUpdated time.Time `json:"dateUpdated,required" format:"date-time"`
- InviteCount int64 `json:"inviteCount,required"`
- MemberCount int64 `json:"memberCount,required"`
- Name string `json:"name,required"`
- PeriodEndDate time.Time `json:"periodEndDate,required,nullable" format:"date-time"`
- PeriodStartDate time.Time `json:"periodStartDate,required,nullable" format:"date-time"`
- ProjectCount int64 `json:"projectCount,required"`
- Slug string `json:"slug,required"`
- Status InferencePipelineUpdateResponseWorkspaceStatus `json:"status,required"`
- MonthlyUsage []InferencePipelineUpdateResponseWorkspaceMonthlyUsage `json:"monthlyUsage"`
- SAMLOnlyAccess bool `json:"samlOnlyAccess"`
- WildcardDomains []string `json:"wildcardDomains"`
- JSON inferencePipelineUpdateResponseWorkspaceJSON `json:"-"`
+ // The workspace id.
+ ID string `json:"id,required" format:"uuid"`
+ // The workspace creator id.
+ CreatorID string `json:"creatorId,required,nullable" format:"uuid"`
+ // The workspace creation date.
+ DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
+ // The workspace last updated date.
+ DateUpdated time.Time `json:"dateUpdated,required" format:"date-time"`
+ // The number of invites in the workspace.
+ InviteCount int64 `json:"inviteCount,required"`
+ // The number of members in the workspace.
+ MemberCount int64 `json:"memberCount,required"`
+ // The workspace name.
+ Name string `json:"name,required"`
+ // The end date of the current billing period.
+ PeriodEndDate time.Time `json:"periodEndDate,required,nullable" format:"date-time"`
+ // The start date of the current billing period.
+ PeriodStartDate time.Time `json:"periodStartDate,required,nullable" format:"date-time"`
+ // The number of projects in the workspace.
+ ProjectCount int64 `json:"projectCount,required"`
+ // The workspace slug.
+ Slug string `json:"slug,required"`
+ Status InferencePipelineUpdateResponseWorkspaceStatus `json:"status,required"`
+ MonthlyUsage []InferencePipelineUpdateResponseWorkspaceMonthlyUsage `json:"monthlyUsage"`
+ // Whether the workspace only allows SAML authentication.
+ SAMLOnlyAccess bool `json:"samlOnlyAccess"`
+ WildcardDomains []string `json:"wildcardDomains"`
+ JSON inferencePipelineUpdateResponseWorkspaceJSON `json:"-"`
}
// inferencePipelineUpdateResponseWorkspaceJSON contains the JSON metadata for the
diff --git a/internal/apiform/encoder.go b/internal/apiform/encoder.go
index baaa704..6fad127 100644
--- a/internal/apiform/encoder.go
+++ b/internal/apiform/encoder.go
@@ -315,11 +315,13 @@ func (e *encoder) newReaderTypeEncoder() encoderFunc {
reader := value.Convert(reflect.TypeOf((*io.Reader)(nil)).Elem()).Interface().(io.Reader)
filename := "anonymous_file"
contentType := "application/octet-stream"
- if named, ok := reader.(interface{ Name() string }); ok {
+ if named, ok := reader.(interface{ Filename() string }); ok {
+ filename = named.Filename()
+ } else if named, ok := reader.(interface{ Name() string }); ok {
filename = path.Base(named.Name())
}
if typed, ok := reader.(interface{ ContentType() string }); ok {
- contentType = path.Base(typed.ContentType())
+ contentType = typed.ContentType()
}
// Below is taken almost 1-for-1 from [multipart.CreateFormFile]
diff --git a/internal/apijson/encoder.go b/internal/apijson/encoder.go
index 6577f2d..a31fcd4 100644
--- a/internal/apijson/encoder.go
+++ b/internal/apijson/encoder.go
@@ -143,7 +143,7 @@ func (e *encoder) newPrimitiveTypeEncoder(t reflect.Type) encoderFunc {
// code more and this current code shouldn't cause any issues
case reflect.String:
return func(v reflect.Value) ([]byte, error) {
- return []byte(fmt.Sprintf("%q", v.String())), nil
+ return json.Marshal(v.Interface())
}
case reflect.Bool:
return func(v reflect.Value) ([]byte, error) {
diff --git a/internal/apijson/port.go b/internal/apijson/port.go
index 80b323b..502ab77 100644
--- a/internal/apijson/port.go
+++ b/internal/apijson/port.go
@@ -34,22 +34,35 @@ func Port(from any, to any) error {
fromJSON := fromVal.FieldByName("JSON")
toJSON := toVal.FieldByName("JSON")
- // First, iterate through the from fields and load all the "normal" fields in the struct to the map of
- // string to reflect.Value, as well as their raw .JSON.Foo counterpart.
- for i := 0; i < fromType.NumField(); i++ {
- field := fromType.Field(i)
- ptag, ok := parseJSONStructTag(field)
- if !ok {
- continue
- }
- if ptag.name == "-" {
- continue
+ // Iterate through the fields of v and load all the "normal" fields in the struct to the map of
+ // string to reflect.Value, as well as their raw .JSON.Foo counterpart indicated by j.
+ var getFields func(t reflect.Type, v reflect.Value)
+ getFields = func(t reflect.Type, v reflect.Value) {
+ j := v.FieldByName("JSON")
+
+ // Recurse into anonymous fields first, since the fields on the object should win over the fields in the
+ // embedded object.
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+ if field.Anonymous {
+ getFields(field.Type, v.Field(i))
+ continue
+ }
}
- values[ptag.name] = fromVal.Field(i)
- if fromJSON.IsValid() {
- fields[ptag.name] = fromJSON.FieldByName(field.Name)
+
+ for i := 0; i < t.NumField(); i++ {
+ field := t.Field(i)
+ ptag, ok := parseJSONStructTag(field)
+ if !ok || ptag.name == "-" {
+ continue
+ }
+ values[ptag.name] = v.Field(i)
+ if j.IsValid() {
+ fields[ptag.name] = j.FieldByName(field.Name)
+ }
}
}
+ getFields(fromType, fromVal)
// Use the values from the previous step to populate the 'to' struct.
for i := 0; i < toType.NumField(); i++ {
diff --git a/internal/apijson/port_test.go b/internal/apijson/port_test.go
index f9b6e3f..1154053 100644
--- a/internal/apijson/port_test.go
+++ b/internal/apijson/port_test.go
@@ -94,6 +94,39 @@ type CardMastercardData struct {
Bar int64 `json:"bar"`
}
+type CommonFields struct {
+ Metadata Metadata `json:"metadata"`
+ Value string `json:"value"`
+
+ JSON commonFieldsJSON
+}
+
+type commonFieldsJSON struct {
+ Metadata Field
+ Value Field
+ ExtraFields map[string]Field
+ raw string
+}
+
+type CardEmbedded struct {
+ CommonFields
+ Processor CardVisaProcessor `json:"processor"`
+ Data CardVisaData `json:"data"`
+ IsFoo bool `json:"is_foo"`
+
+ JSON cardEmbeddedJSON
+}
+
+type cardEmbeddedJSON struct {
+ Processor Field
+ Data Field
+ IsFoo Field
+ ExtraFields map[string]Field
+ raw string
+}
+
+func (r cardEmbeddedJSON) RawJSON() string { return r.raw }
+
var portTests = map[string]struct {
from any
to any
@@ -158,6 +191,52 @@ var portTests = map[string]struct {
Value: false,
},
},
+ "embedded to card": {
+ CardEmbedded{
+ CommonFields: CommonFields{
+ Metadata: Metadata{
+ CreatedAt: "Mar 29 2024",
+ },
+ Value: "embedded_value",
+ JSON: commonFieldsJSON{
+ Metadata: Field{raw: `{"created_at":"Mar 29 2024"}`, status: valid},
+ Value: Field{raw: `"embedded_value"`, status: valid},
+ raw: `should not matter`,
+ },
+ },
+ Processor: "visa",
+ IsFoo: true,
+ Data: CardVisaData{
+ Foo: "embedded_foo",
+ },
+ JSON: cardEmbeddedJSON{
+ raw: `{"processor":"visa","is_foo":true,"data":{"foo":"embedded_foo"},"metadata":{"created_at":"Mar 29 2024"},"value":"embedded_value"}`,
+ Processor: Field{raw: `"visa"`, status: valid},
+ IsFoo: Field{raw: `true`, status: valid},
+ Data: Field{raw: `{"foo":"embedded_foo"}`, status: valid},
+ },
+ },
+ Card{
+ Processor: "visa",
+ IsFoo: true,
+ IsBar: false,
+ Data: CardVisaData{
+ Foo: "embedded_foo",
+ },
+ Metadata: Metadata{
+ CreatedAt: "Mar 29 2024",
+ },
+ Value: "embedded_value",
+ JSON: cardJSON{
+ raw: `{"processor":"visa","is_foo":true,"data":{"foo":"embedded_foo"},"metadata":{"created_at":"Mar 29 2024"},"value":"embedded_value"}`,
+ Processor: Field{raw: `"visa"`, status: 0x3},
+ IsFoo: Field{raw: "true", status: 0x3},
+ Data: Field{raw: `{"foo":"embedded_foo"}`, status: 0x3},
+ Metadata: Field{raw: `{"created_at":"Mar 29 2024"}`, status: 0x3},
+ Value: Field{raw: `"embedded_value"`, status: 0x3},
+ },
+ },
+ },
}
func TestPort(t *testing.T) {
diff --git a/internal/apijson/registry.go b/internal/apijson/registry.go
index 2ea00ae..119cc5f 100644
--- a/internal/apijson/registry.go
+++ b/internal/apijson/registry.go
@@ -29,3 +29,13 @@ func RegisterUnion(typ reflect.Type, discriminator string, variants ...UnionVari
unionVariants[variant.Type] = typ
}
}
+
+// Useful to wrap a union type to force it to use [apijson.UnmarshalJSON] since you cannot define an
+// UnmarshalJSON function on the interface itself.
+type UnionUnmarshaler[T any] struct {
+ Value T
+}
+
+func (c *UnionUnmarshaler[T]) UnmarshalJSON(buf []byte) error {
+ return UnmarshalRoot(buf, &c.Value)
+}
diff --git a/internal/requestconfig/requestconfig.go b/internal/requestconfig/requestconfig.go
index d925eab..3502bf5 100644
--- a/internal/requestconfig/requestconfig.go
+++ b/internal/requestconfig/requestconfig.go
@@ -138,6 +138,7 @@ func NewRequestConfig(ctx context.Context, method string, u string, body interfa
req.Header.Set("Accept", "application/json")
req.Header.Set("X-Stainless-Retry-Count", "0")
+ req.Header.Set("X-Stainless-Timeout", "0")
for k, v := range getDefaultHeaders() {
req.Header.Add(k, v)
}
@@ -157,6 +158,18 @@ func NewRequestConfig(ctx context.Context, method string, u string, body interfa
if err != nil {
return nil, err
}
+
+ // This must run after `cfg.Apply(...)` above in case the request timeout gets modified. We also only
+ // apply our own logic for it if it's still "0" from above. If it's not, then it was deleted or modified
+ // by the user and we should respect that.
+ if req.Header.Get("X-Stainless-Timeout") == "0" {
+ if cfg.RequestTimeout == time.Duration(0) {
+ req.Header.Del("X-Stainless-Timeout")
+ } else {
+ req.Header.Set("X-Stainless-Timeout", strconv.Itoa(int(cfg.RequestTimeout.Seconds())))
+ }
+ }
+
return &cfg, nil
}
@@ -279,6 +292,41 @@ func parseRetryAfterHeader(resp *http.Response) (time.Duration, bool) {
return 0, false
}
+// isBeforeContextDeadline reports whether the non-zero Time t is
+// before ctx's deadline. If ctx does not have a deadline, it
+// always reports true (the deadline is considered infinite).
+func isBeforeContextDeadline(t time.Time, ctx context.Context) bool {
+ d, ok := ctx.Deadline()
+ if !ok {
+ return true
+ }
+ return t.Before(d)
+}
+
+// bodyWithTimeout is an io.ReadCloser which can observe a context's cancel func
+// to handle timeouts etc. It wraps an existing io.ReadCloser.
+type bodyWithTimeout struct {
+ stop func() // stops the time.Timer waiting to cancel the request
+ rc io.ReadCloser
+}
+
+func (b *bodyWithTimeout) Read(p []byte) (n int, err error) {
+ n, err = b.rc.Read(p)
+ if err == nil {
+ return n, nil
+ }
+ if err == io.EOF {
+ return n, err
+ }
+ return n, err
+}
+
+func (b *bodyWithTimeout) Close() error {
+ err := b.rc.Close()
+ b.stop()
+ return err
+}
+
func retryDelay(res *http.Response, retryCount int) time.Duration {
// If the API asks us to wait a certain amount of time (and it's a reasonable amount),
// just do what it says.
@@ -340,12 +388,17 @@ func (cfg *RequestConfig) Execute() (err error) {
shouldSendRetryCount := cfg.Request.Header.Get("X-Stainless-Retry-Count") == "0"
var res *http.Response
+ var cancel context.CancelFunc
for retryCount := 0; retryCount <= cfg.MaxRetries; retryCount += 1 {
ctx := cfg.Request.Context()
- if cfg.RequestTimeout != time.Duration(0) {
- var cancel context.CancelFunc
+ if cfg.RequestTimeout != time.Duration(0) && isBeforeContextDeadline(time.Now().Add(cfg.RequestTimeout), ctx) {
ctx, cancel = context.WithTimeout(ctx, cfg.RequestTimeout)
- defer cancel()
+ defer func() {
+ // The cancel function is nil if it was handed off to be handled in a different scope.
+ if cancel != nil {
+ cancel()
+ }
+ }()
}
req := cfg.Request.Clone(ctx)
@@ -413,10 +466,15 @@ func (cfg *RequestConfig) Execute() (err error) {
return &aerr
}
- if cfg.ResponseBodyInto == nil {
- return nil
- }
- if _, ok := cfg.ResponseBodyInto.(**http.Response); ok {
+ _, intoCustomResponseBody := cfg.ResponseBodyInto.(**http.Response)
+ if cfg.ResponseBodyInto == nil || intoCustomResponseBody {
+ // We aren't reading the response body in this scope, but whoever is will need the
+ // cancel func from the context to observe request timeouts.
+ // Put the cancel function in the response body so it can be handled elsewhere.
+ if cancel != nil {
+ res.Body = &bodyWithTimeout{rc: res.Body, stop: cancel}
+ cancel = nil
+ }
return nil
}
diff --git a/internal/version.go b/internal/version.go
index 805f4ff..5f0be5b 100644
--- a/internal/version.go
+++ b/internal/version.go
@@ -2,4 +2,4 @@
package internal
-const PackageVersion = "0.1.0-alpha.13" // x-release-please-version
+const PackageVersion = "0.1.0-alpha.14" // x-release-please-version
diff --git a/projectinferencepipeline.go b/projectinferencepipeline.go
index 64e788f..a1f805c 100644
--- a/projectinferencepipeline.go
+++ b/projectinferencepipeline.go
@@ -338,22 +338,34 @@ func (r projectInferencePipelineNewResponseProjectGitRepoJSON) RawJSON() string
}
type ProjectInferencePipelineNewResponseWorkspace struct {
- ID string `json:"id,required" format:"uuid"`
- CreatorID string `json:"creatorId,required,nullable" format:"uuid"`
- DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
- DateUpdated time.Time `json:"dateUpdated,required" format:"date-time"`
- InviteCount int64 `json:"inviteCount,required"`
- MemberCount int64 `json:"memberCount,required"`
- Name string `json:"name,required"`
- PeriodEndDate time.Time `json:"periodEndDate,required,nullable" format:"date-time"`
- PeriodStartDate time.Time `json:"periodStartDate,required,nullable" format:"date-time"`
- ProjectCount int64 `json:"projectCount,required"`
- Slug string `json:"slug,required"`
- Status ProjectInferencePipelineNewResponseWorkspaceStatus `json:"status,required"`
- MonthlyUsage []ProjectInferencePipelineNewResponseWorkspaceMonthlyUsage `json:"monthlyUsage"`
- SAMLOnlyAccess bool `json:"samlOnlyAccess"`
- WildcardDomains []string `json:"wildcardDomains"`
- JSON projectInferencePipelineNewResponseWorkspaceJSON `json:"-"`
+ // The workspace id.
+ ID string `json:"id,required" format:"uuid"`
+ // The workspace creator id.
+ CreatorID string `json:"creatorId,required,nullable" format:"uuid"`
+ // The workspace creation date.
+ DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
+ // The workspace last updated date.
+ DateUpdated time.Time `json:"dateUpdated,required" format:"date-time"`
+ // The number of invites in the workspace.
+ InviteCount int64 `json:"inviteCount,required"`
+ // The number of members in the workspace.
+ MemberCount int64 `json:"memberCount,required"`
+ // The workspace name.
+ Name string `json:"name,required"`
+ // The end date of the current billing period.
+ PeriodEndDate time.Time `json:"periodEndDate,required,nullable" format:"date-time"`
+ // The start date of the current billing period.
+ PeriodStartDate time.Time `json:"periodStartDate,required,nullable" format:"date-time"`
+ // The number of projects in the workspace.
+ ProjectCount int64 `json:"projectCount,required"`
+ // The workspace slug.
+ Slug string `json:"slug,required"`
+ Status ProjectInferencePipelineNewResponseWorkspaceStatus `json:"status,required"`
+ MonthlyUsage []ProjectInferencePipelineNewResponseWorkspaceMonthlyUsage `json:"monthlyUsage"`
+ // Whether the workspace only allows SAML authentication.
+ SAMLOnlyAccess bool `json:"samlOnlyAccess"`
+ WildcardDomains []string `json:"wildcardDomains"`
+ JSON projectInferencePipelineNewResponseWorkspaceJSON `json:"-"`
}
// projectInferencePipelineNewResponseWorkspaceJSON contains the JSON metadata for
@@ -733,22 +745,34 @@ func (r projectInferencePipelineListResponseItemsProjectGitRepoJSON) RawJSON() s
}
type ProjectInferencePipelineListResponseItemsWorkspace struct {
- ID string `json:"id,required" format:"uuid"`
- CreatorID string `json:"creatorId,required,nullable" format:"uuid"`
- DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
- DateUpdated time.Time `json:"dateUpdated,required" format:"date-time"`
- InviteCount int64 `json:"inviteCount,required"`
- MemberCount int64 `json:"memberCount,required"`
- Name string `json:"name,required"`
- PeriodEndDate time.Time `json:"periodEndDate,required,nullable" format:"date-time"`
- PeriodStartDate time.Time `json:"periodStartDate,required,nullable" format:"date-time"`
- ProjectCount int64 `json:"projectCount,required"`
- Slug string `json:"slug,required"`
- Status ProjectInferencePipelineListResponseItemsWorkspaceStatus `json:"status,required"`
- MonthlyUsage []ProjectInferencePipelineListResponseItemsWorkspaceMonthlyUsage `json:"monthlyUsage"`
- SAMLOnlyAccess bool `json:"samlOnlyAccess"`
- WildcardDomains []string `json:"wildcardDomains"`
- JSON projectInferencePipelineListResponseItemsWorkspaceJSON `json:"-"`
+ // The workspace id.
+ ID string `json:"id,required" format:"uuid"`
+ // The workspace creator id.
+ CreatorID string `json:"creatorId,required,nullable" format:"uuid"`
+ // The workspace creation date.
+ DateCreated time.Time `json:"dateCreated,required" format:"date-time"`
+ // The workspace last updated date.
+ DateUpdated time.Time `json:"dateUpdated,required" format:"date-time"`
+ // The number of invites in the workspace.
+ InviteCount int64 `json:"inviteCount,required"`
+ // The number of members in the workspace.
+ MemberCount int64 `json:"memberCount,required"`
+ // The workspace name.
+ Name string `json:"name,required"`
+ // The end date of the current billing period.
+ PeriodEndDate time.Time `json:"periodEndDate,required,nullable" format:"date-time"`
+ // The start date of the current billing period.
+ PeriodStartDate time.Time `json:"periodStartDate,required,nullable" format:"date-time"`
+ // The number of projects in the workspace.
+ ProjectCount int64 `json:"projectCount,required"`
+ // The workspace slug.
+ Slug string `json:"slug,required"`
+ Status ProjectInferencePipelineListResponseItemsWorkspaceStatus `json:"status,required"`
+ MonthlyUsage []ProjectInferencePipelineListResponseItemsWorkspaceMonthlyUsage `json:"monthlyUsage"`
+ // Whether the workspace only allows SAML authentication.
+ SAMLOnlyAccess bool `json:"samlOnlyAccess"`
+ WildcardDomains []string `json:"wildcardDomains"`
+ JSON projectInferencePipelineListResponseItemsWorkspaceJSON `json:"-"`
}
// projectInferencePipelineListResponseItemsWorkspaceJSON contains the JSON
@@ -910,9 +934,13 @@ func (r ProjectInferencePipelineNewParamsProjectGitRepo) MarshalJSON() (data []b
}
type ProjectInferencePipelineNewParamsWorkspace struct {
- Name param.Field[string] `json:"name,required"`
- Slug param.Field[string] `json:"slug,required"`
- InviteCode param.Field[string] `json:"inviteCode"`
+ // The workspace name.
+ Name param.Field[string] `json:"name,required"`
+ // The workspace slug.
+ Slug param.Field[string] `json:"slug,required"`
+ // The workspace invite code.
+ InviteCode param.Field[string] `json:"inviteCode"`
+ // Whether the workspace only allows SAML authentication.
SAMLOnlyAccess param.Field[bool] `json:"samlOnlyAccess"`
WildcardDomains param.Field[[]string] `json:"wildcardDomains"`
}
diff --git a/usage_test.go b/usage_test.go
index e535374..20d506e 100644
--- a/usage_test.go
+++ b/usage_test.go
@@ -38,9 +38,9 @@ func TestUsage(t *testing.T) {
Rows: openlayer.F([]map[string]interface{}{{
"user_query": "what is the meaning of life?",
"output": "42",
- "tokens": map[string]interface{}{},
- "cost": map[string]interface{}{},
- "timestamp": map[string]interface{}{},
+ "tokens": 7,
+ "cost": 0.02,
+ "timestamp": 1610000000,
}}),
},
)