diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index cb9d254..7f3f5c8 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.22.0"
+ ".": "0.23.0"
}
\ No newline at end of file
diff --git a/.stats.yml b/.stats.yml
index 0c474bb..135345a 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,4 +1,4 @@
-configured_endpoints: 80
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-8a37652fa586b8932466d16285359a89988505f850787f8257d0c4c7053da173.yml
-openapi_spec_hash: 042765a113f6d08109e8146b302323ec
-config_hash: 113f1e5bc3567628a5d51c70bc00969d
+configured_endpoints: 82
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/kernel%2Fkernel-dac11bdb857e700a8c39d183e753ddd1ebaaca69fd9fc5ee57d6b56b70b00e6e.yml
+openapi_spec_hash: 78fbc50dd0b61cdc87564fbea278ee23
+config_hash: a4b4d14bdf6af723b235a6981977627c
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2abbe96..c17fef6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,28 @@
# Changelog
+## 0.23.0 (2025-12-16)
+
+Full Changelog: [v0.22.0...v0.23.0](https://github.com/onkernel/kernel-go-sdk/compare/v0.22.0...v0.23.0)
+
+### Features
+
+* **encoder:** support bracket encoding form-data object members ([7d11b85](https://github.com/onkernel/kernel-go-sdk/commit/7d11b85f517bfa5875440c516de735009fbd05a0))
+* enhance agent authentication API with new endpoints and request… ([7f2d67a](https://github.com/onkernel/kernel-go-sdk/commit/7f2d67aeba880e8d35b084ffa6f0c2364f88378a))
+* Enhance AuthAgent model with last_auth_check_at field ([a3cb1e1](https://github.com/onkernel/kernel-go-sdk/commit/a3cb1e13b7700f1ccce3393411a08f822e216d1f))
+
+
+### Bug Fixes
+
+* **client:** copy over change to params names to ExecuteNewRequeest ([92fd6c1](https://github.com/onkernel/kernel-go-sdk/commit/92fd6c10cb2c451f9381d3969c2aa80b121addfe))
+* **mcp:** correct code tool API endpoint ([563016a](https://github.com/onkernel/kernel-go-sdk/commit/563016aabd8010af7bf2d1db0b7436f31b0fd23e))
+* rename param to avoid collision ([a20c158](https://github.com/onkernel/kernel-go-sdk/commit/a20c1588a19c48cfa6503af80c0ba6ad4add76f7))
+
+
+### Chores
+
+* elide duplicate aliases ([9eb4ec3](https://github.com/onkernel/kernel-go-sdk/commit/9eb4ec3048ab55e534e84de255ca0f2d22d5f233))
+* **internal:** codegen related update ([839598d](https://github.com/onkernel/kernel-go-sdk/commit/839598d5a188b64afe16e1df16915c94f822b309))
+
## 0.22.0 (2025-12-06)
Full Changelog: [v0.21.0...v0.22.0](https://github.com/onkernel/kernel-go-sdk/compare/v0.21.0...v0.22.0)
diff --git a/README.md b/README.md
index 43fd6a5..ab51c2e 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@ Or to pin the version:
```sh
-go get -u 'github.com/onkernel/kernel-go-sdk@v0.22.0'
+go get -u 'github.com/onkernel/kernel-go-sdk@v0.23.0'
```
diff --git a/agentauth.go b/agentauth.go
index 16311d1..b2c534f 100644
--- a/agentauth.go
+++ b/agentauth.go
@@ -4,15 +4,20 @@ package kernel
import (
"context"
+ "encoding/json"
"errors"
"fmt"
"net/http"
+ "net/url"
"slices"
"time"
"github.com/onkernel/kernel-go-sdk/internal/apijson"
+ "github.com/onkernel/kernel-go-sdk/internal/apiquery"
+ shimjson "github.com/onkernel/kernel-go-sdk/internal/encoding/json"
"github.com/onkernel/kernel-go-sdk/internal/requestconfig"
"github.com/onkernel/kernel-go-sdk/option"
+ "github.com/onkernel/kernel-go-sdk/packages/pagination"
"github.com/onkernel/kernel-go-sdk/packages/param"
"github.com/onkernel/kernel-go-sdk/packages/respjson"
)
@@ -38,6 +43,17 @@ func NewAgentAuthService(opts ...option.RequestOption) (r AgentAuthService) {
return
}
+// Creates a new auth agent for the specified domain and profile combination, or
+// returns an existing one if it already exists. This is idempotent - calling with
+// the same domain and profile will return the same agent. Does NOT start an
+// invocation - use POST /agents/auth/invocations to start an auth flow.
+func (r *AgentAuthService) New(ctx context.Context, body AgentAuthNewParams, opts ...option.RequestOption) (res *AuthAgent, err error) {
+ opts = slices.Concat(r.Options, opts)
+ path := "agents/auth"
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
+ return
+}
+
// Retrieve an auth agent by its ID. Returns the current authentication status of
// the managed profile.
func (r *AgentAuthService) Get(ctx context.Context, id string, opts ...option.RequestOption) (res *AuthAgent, err error) {
@@ -51,14 +67,27 @@ func (r *AgentAuthService) Get(ctx context.Context, id string, opts ...option.Re
return
}
-// Creates a browser session and returns a handoff code for the hosted flow. Uses
-// standard API key or JWT authentication (not the JWT returned by the exchange
-// endpoint).
-func (r *AgentAuthService) Start(ctx context.Context, body AgentAuthStartParams, opts ...option.RequestOption) (res *AgentAuthStartResponse, err error) {
+// List auth agents with optional filters for profile_name and target_domain.
+func (r *AgentAuthService) List(ctx context.Context, query AgentAuthListParams, opts ...option.RequestOption) (res *pagination.OffsetPagination[AuthAgent], err error) {
+ var raw *http.Response
opts = slices.Concat(r.Options, opts)
- path := "agents/auth/start"
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
- return
+ opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
+ path := "agents/auth"
+ cfg, err := requestconfig.NewRequestConfig(ctx, http.MethodGet, path, query, &res, opts...)
+ if err != nil {
+ return nil, err
+ }
+ err = cfg.Execute()
+ if err != nil {
+ return nil, err
+ }
+ res.SetPageConfig(cfg, raw)
+ return res, nil
+}
+
+// List auth agents with optional filters for profile_name and target_domain.
+func (r *AgentAuthService) ListAutoPaging(ctx context.Context, query AgentAuthListParams, opts ...option.RequestOption) *pagination.OffsetPaginationAutoPager[AuthAgent] {
+ return pagination.NewOffsetPaginationAutoPager(r.List(ctx, query, opts...))
}
// Response from discover endpoint matching AuthBlueprint schema
@@ -133,36 +162,6 @@ const (
AgentAuthInvocationResponseStatusCanceled AgentAuthInvocationResponseStatus = "CANCELED"
)
-// Response from starting an agent authentication invocation
-type AgentAuthStartResponse struct {
- // Unique identifier for the auth agent managing this domain/profile
- AuthAgentID string `json:"auth_agent_id,required"`
- // When the handoff code expires
- ExpiresAt time.Time `json:"expires_at,required" format:"date-time"`
- // One-time code for handoff
- HandoffCode string `json:"handoff_code,required"`
- // URL to redirect user to
- HostedURL string `json:"hosted_url,required" format:"uri"`
- // Unique identifier for the invocation
- InvocationID string `json:"invocation_id,required"`
- // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
- JSON struct {
- AuthAgentID respjson.Field
- ExpiresAt respjson.Field
- HandoffCode respjson.Field
- HostedURL respjson.Field
- InvocationID respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
- } `json:"-"`
-}
-
-// Returns the unmodified JSON received from the API
-func (r AgentAuthStartResponse) RawJSON() string { return r.JSON.raw }
-func (r *AgentAuthStartResponse) UnmarshalJSON(data []byte) error {
- return apijson.UnmarshalRoot(data, r)
-}
-
// Response from submit endpoint matching SubmitResult schema
type AgentAuthSubmitResponse struct {
// Whether submission succeeded
@@ -213,14 +212,17 @@ type AuthAgent struct {
//
// Any of "AUTHENTICATED", "NEEDS_AUTH".
Status AuthAgentStatus `json:"status,required"`
+ // When the last authentication check was performed
+ LastAuthCheckAt time.Time `json:"last_auth_check_at" format:"date-time"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
- ID respjson.Field
- Domain respjson.Field
- ProfileName respjson.Field
- Status respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
+ ID respjson.Field
+ Domain respjson.Field
+ ProfileName respjson.Field
+ Status respjson.Field
+ LastAuthCheckAt respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
} `json:"-"`
}
@@ -238,6 +240,89 @@ const (
AuthAgentStatusNeedsAuth AuthAgentStatus = "NEEDS_AUTH"
)
+// Request to create or find an auth agent
+//
+// The properties ProfileName, TargetDomain are required.
+type AuthAgentCreateRequestParam struct {
+ // Name of the profile to use for this auth agent
+ ProfileName string `json:"profile_name,required"`
+ // Target domain for authentication
+ TargetDomain string `json:"target_domain,required"`
+ // Optional login page URL. If provided, will be stored on the agent and used to
+ // skip discovery in future invocations.
+ LoginURL param.Opt[string] `json:"login_url,omitzero" format:"uri"`
+ // Optional proxy configuration
+ Proxy AuthAgentCreateRequestProxyParam `json:"proxy,omitzero"`
+ paramObj
+}
+
+func (r AuthAgentCreateRequestParam) MarshalJSON() (data []byte, err error) {
+ type shadow AuthAgentCreateRequestParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *AuthAgentCreateRequestParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// Optional proxy configuration
+type AuthAgentCreateRequestProxyParam struct {
+ // ID of the proxy to use
+ ProxyID param.Opt[string] `json:"proxy_id,omitzero"`
+ paramObj
+}
+
+func (r AuthAgentCreateRequestProxyParam) MarshalJSON() (data []byte, err error) {
+ type shadow AuthAgentCreateRequestProxyParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *AuthAgentCreateRequestProxyParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// Request to create an invocation for an existing auth agent
+//
+// The property AuthAgentID is required.
+type AuthAgentInvocationCreateRequestParam struct {
+ // ID of the auth agent to create an invocation for
+ AuthAgentID string `json:"auth_agent_id,required"`
+ paramObj
+}
+
+func (r AuthAgentInvocationCreateRequestParam) MarshalJSON() (data []byte, err error) {
+ type shadow AuthAgentInvocationCreateRequestParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *AuthAgentInvocationCreateRequestParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// Response from creating an auth agent invocation
+type AuthAgentInvocationCreateResponse struct {
+ // When the handoff code expires
+ ExpiresAt time.Time `json:"expires_at,required" format:"date-time"`
+ // One-time code for handoff
+ HandoffCode string `json:"handoff_code,required"`
+ // URL to redirect user to
+ HostedURL string `json:"hosted_url,required" format:"uri"`
+ // Unique identifier for the invocation
+ InvocationID string `json:"invocation_id,required"`
+ // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
+ JSON struct {
+ ExpiresAt respjson.Field
+ HandoffCode respjson.Field
+ HostedURL respjson.Field
+ InvocationID respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+// Returns the unmodified JSON received from the API
+func (r AuthAgentInvocationCreateResponse) RawJSON() string { return r.JSON.raw }
+func (r *AuthAgentInvocationCreateResponse) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
// A discovered form field
type DiscoveredField struct {
// Field label
@@ -286,40 +371,35 @@ const (
DiscoveredFieldTypeCode DiscoveredFieldType = "code"
)
-type AgentAuthStartParams struct {
- // Name of the profile to use for this flow
- ProfileName string `json:"profile_name,required"`
- // Target domain for authentication
- TargetDomain string `json:"target_domain,required"`
- // Optional logo URL for the application
- AppLogoURL param.Opt[string] `json:"app_logo_url,omitzero" format:"uri"`
- // Optional login page URL. If provided, will be stored on the agent and used to
- // skip Phase 1 discovery in future invocations.
- LoginURL param.Opt[string] `json:"login_url,omitzero" format:"uri"`
- // Optional proxy configuration
- Proxy AgentAuthStartParamsProxy `json:"proxy,omitzero"`
+type AgentAuthNewParams struct {
+ // Request to create or find an auth agent
+ AuthAgentCreateRequest AuthAgentCreateRequestParam
paramObj
}
-func (r AgentAuthStartParams) MarshalJSON() (data []byte, err error) {
- type shadow AgentAuthStartParams
- return param.MarshalObject(r, (*shadow)(&r))
+func (r AgentAuthNewParams) MarshalJSON() (data []byte, err error) {
+ return shimjson.Marshal(r.AuthAgentCreateRequest)
}
-func (r *AgentAuthStartParams) UnmarshalJSON(data []byte) error {
- return apijson.UnmarshalRoot(data, r)
+func (r *AgentAuthNewParams) UnmarshalJSON(data []byte) error {
+ return json.Unmarshal(data, &r.AuthAgentCreateRequest)
}
-// Optional proxy configuration
-type AgentAuthStartParamsProxy struct {
- // ID of the proxy to use
- ProxyID param.Opt[string] `json:"proxy_id,omitzero"`
+type AgentAuthListParams struct {
+ // Maximum number of results to return
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ // Number of results to skip
+ Offset param.Opt[int64] `query:"offset,omitzero" json:"-"`
+ // Filter by profile name
+ ProfileName param.Opt[string] `query:"profile_name,omitzero" json:"-"`
+ // Filter by target domain
+ TargetDomain param.Opt[string] `query:"target_domain,omitzero" json:"-"`
paramObj
}
-func (r AgentAuthStartParamsProxy) MarshalJSON() (data []byte, err error) {
- type shadow AgentAuthStartParamsProxy
- return param.MarshalObject(r, (*shadow)(&r))
-}
-func (r *AgentAuthStartParamsProxy) UnmarshalJSON(data []byte) error {
- return apijson.UnmarshalRoot(data, r)
+// URLQuery serializes [AgentAuthListParams]'s query parameters as `url.Values`.
+func (r AgentAuthListParams) URLQuery() (v url.Values, err error) {
+ return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{
+ ArrayFormat: apiquery.ArrayQueryFormatComma,
+ NestedFormat: apiquery.NestedQueryFormatBrackets,
+ })
}
diff --git a/agentauth_test.go b/agentauth_test.go
index aa21286..7cc8517 100644
--- a/agentauth_test.go
+++ b/agentauth_test.go
@@ -13,6 +13,38 @@ import (
"github.com/onkernel/kernel-go-sdk/option"
)
+func TestAgentAuthNewWithOptionalParams(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ _, err := client.Agents.Auth.New(context.TODO(), kernel.AgentAuthNewParams{
+ AuthAgentCreateRequest: kernel.AuthAgentCreateRequestParam{
+ ProfileName: "user-123",
+ TargetDomain: "netflix.com",
+ LoginURL: kernel.String("https://netflix.com/login"),
+ Proxy: kernel.AuthAgentCreateRequestProxyParam{
+ ProxyID: kernel.String("proxy_id"),
+ },
+ },
+ })
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
+
func TestAgentAuthGet(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
@@ -36,7 +68,7 @@ func TestAgentAuthGet(t *testing.T) {
}
}
-func TestAgentAuthStartWithOptionalParams(t *testing.T) {
+func TestAgentAuthListWithOptionalParams(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
@@ -49,14 +81,11 @@ func TestAgentAuthStartWithOptionalParams(t *testing.T) {
option.WithBaseURL(baseURL),
option.WithAPIKey("My API Key"),
)
- _, err := client.Agents.Auth.Start(context.TODO(), kernel.AgentAuthStartParams{
- ProfileName: "auth-abc123",
- TargetDomain: "doordash.com",
- AppLogoURL: kernel.String("https://example.com/logo.png"),
- LoginURL: kernel.String("https://doordash.com/account/login"),
- Proxy: kernel.AgentAuthStartParamsProxy{
- ProxyID: kernel.String("proxy_id"),
- },
+ _, err := client.Agents.Auth.List(context.TODO(), kernel.AgentAuthListParams{
+ Limit: kernel.Int(100),
+ Offset: kernel.Int(0),
+ ProfileName: kernel.String("profile_name"),
+ TargetDomain: kernel.String("target_domain"),
})
if err != nil {
var apierr *kernel.Error
diff --git a/agentauthinvocation.go b/agentauthinvocation.go
index e9b8ccb..3a12d03 100644
--- a/agentauthinvocation.go
+++ b/agentauthinvocation.go
@@ -4,12 +4,14 @@ package kernel
import (
"context"
+ "encoding/json"
"errors"
"fmt"
"net/http"
"slices"
"github.com/onkernel/kernel-go-sdk/internal/apijson"
+ shimjson "github.com/onkernel/kernel-go-sdk/internal/encoding/json"
"github.com/onkernel/kernel-go-sdk/internal/requestconfig"
"github.com/onkernel/kernel-go-sdk/option"
"github.com/onkernel/kernel-go-sdk/packages/param"
@@ -35,6 +37,16 @@ func NewAgentAuthInvocationService(opts ...option.RequestOption) (r AgentAuthInv
return
}
+// Creates a new authentication invocation for the specified auth agent. This
+// starts the auth flow and returns a hosted URL for the user to complete
+// authentication.
+func (r *AgentAuthInvocationService) New(ctx context.Context, body AgentAuthInvocationNewParams, opts ...option.RequestOption) (res *AuthAgentInvocationCreateResponse, err error) {
+ opts = slices.Concat(r.Options, opts)
+ path := "agents/auth/invocations"
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, body, &res, opts...)
+ return
+}
+
// Returns invocation details including app_name and target_domain. Uses the JWT
// returned by the exchange endpoint, or standard API key or JWT authentication.
func (r *AgentAuthInvocationService) Get(ctx context.Context, invocationID string, opts ...option.RequestOption) (res *AgentAuthInvocationResponse, err error) {
@@ -109,6 +121,19 @@ func (r *AgentAuthInvocationExchangeResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+type AgentAuthInvocationNewParams struct {
+ // Request to create an invocation for an existing auth agent
+ AuthAgentInvocationCreateRequest AuthAgentInvocationCreateRequestParam
+ paramObj
+}
+
+func (r AgentAuthInvocationNewParams) MarshalJSON() (data []byte, err error) {
+ return shimjson.Marshal(r.AuthAgentInvocationCreateRequest)
+}
+func (r *AgentAuthInvocationNewParams) UnmarshalJSON(data []byte) error {
+ return json.Unmarshal(data, &r.AuthAgentInvocationCreateRequest)
+}
+
type AgentAuthInvocationDiscoverParams struct {
// Optional login page URL. If provided, will override the stored login URL for
// this discovery invocation and skip Phase 1 discovery.
diff --git a/agentauthinvocation_test.go b/agentauthinvocation_test.go
index 367ff15..d89d3a8 100644
--- a/agentauthinvocation_test.go
+++ b/agentauthinvocation_test.go
@@ -13,6 +13,33 @@ import (
"github.com/onkernel/kernel-go-sdk/option"
)
+func TestAgentAuthInvocationNew(t *testing.T) {
+ t.Skip("Prism tests are disabled")
+ baseURL := "http://localhost:4010"
+ if envURL, ok := os.LookupEnv("TEST_API_BASE_URL"); ok {
+ baseURL = envURL
+ }
+ if !testutil.CheckTestServer(t, baseURL) {
+ return
+ }
+ client := kernel.NewClient(
+ option.WithBaseURL(baseURL),
+ option.WithAPIKey("My API Key"),
+ )
+ _, err := client.Agents.Auth.Invocations.New(context.TODO(), kernel.AgentAuthInvocationNewParams{
+ AuthAgentInvocationCreateRequest: kernel.AuthAgentInvocationCreateRequestParam{
+ AuthAgentID: "abc123xyz",
+ },
+ })
+ if err != nil {
+ var apierr *kernel.Error
+ if errors.As(err, &apierr) {
+ t.Log(string(apierr.DumpRequest(true)))
+ }
+ t.Fatalf("err should be nil: %s", err.Error())
+ }
+}
+
func TestAgentAuthInvocationGet(t *testing.T) {
t.Skip("Prism tests are disabled")
baseURL := "http://localhost:4010"
diff --git a/api.md b/api.md
index 80ddb73..b83ecc8 100644
--- a/api.md
+++ b/api.md
@@ -120,7 +120,7 @@ Methods:
- client.Browsers.Fs.SetFilePermissions(ctx context.Context, id string, body kernel.BrowserFSetFilePermissionsParams) error
- client.Browsers.Fs.Upload(ctx context.Context, id string, body kernel.BrowserFUploadParams) error
- client.Browsers.Fs.UploadZip(ctx context.Context, id string, body kernel.BrowserFUploadZipParams) error
-- client.Browsers.Fs.WriteFile(ctx context.Context, id string, contents io.Reader, body kernel.BrowserFWriteFileParams) error
+- client.Browsers.Fs.WriteFile(ctx context.Context, id string, contents io.Reader, params kernel.BrowserFWriteFileParams) error
### Watch
@@ -258,19 +258,25 @@ Methods:
## Auth
+Params Types:
+
+- kernel.AuthAgentCreateRequestParam
+- kernel.AuthAgentInvocationCreateRequestParam
+
Response Types:
- kernel.AgentAuthDiscoverResponse
- kernel.AgentAuthInvocationResponse
-- kernel.AgentAuthStartResponse
- kernel.AgentAuthSubmitResponse
- kernel.AuthAgent
+- kernel.AuthAgentInvocationCreateResponse
- kernel.DiscoveredField
Methods:
+- client.Agents.Auth.New(ctx context.Context, body kernel.AgentAuthNewParams) (kernel.AuthAgent, error)
- client.Agents.Auth.Get(ctx context.Context, id string) (kernel.AuthAgent, error)
-- client.Agents.Auth.Start(ctx context.Context, body kernel.AgentAuthStartParams) (kernel.AgentAuthStartResponse, error)
+- client.Agents.Auth.List(ctx context.Context, query kernel.AgentAuthListParams) (pagination.OffsetPagination[kernel.AuthAgent], error)
### Invocations
@@ -280,6 +286,7 @@ Response Types:
Methods:
+- client.Agents.Auth.Invocations.New(ctx context.Context, body kernel.AgentAuthInvocationNewParams) (kernel.AuthAgentInvocationCreateResponse, error)
- client.Agents.Auth.Invocations.Get(ctx context.Context, invocationID string) (kernel.AgentAuthInvocationResponse, error)
- client.Agents.Auth.Invocations.Discover(ctx context.Context, invocationID string, body kernel.AgentAuthInvocationDiscoverParams) (kernel.AgentAuthDiscoverResponse, error)
- client.Agents.Auth.Invocations.Exchange(ctx context.Context, invocationID string, body kernel.AgentAuthInvocationExchangeParams) (kernel.AgentAuthInvocationExchangeResponse, error)
diff --git a/browserf.go b/browserf.go
index 4d1c499..ec67a04 100644
--- a/browserf.go
+++ b/browserf.go
@@ -186,7 +186,7 @@ func (r *BrowserFService) UploadZip(ctx context.Context, id string, body Browser
}
// Write or create a file
-func (r *BrowserFService) WriteFile(ctx context.Context, id string, contents io.Reader, body BrowserFWriteFileParams, opts ...option.RequestOption) (err error) {
+func (r *BrowserFService) WriteFile(ctx context.Context, id string, contents io.Reader, params BrowserFWriteFileParams, opts ...option.RequestOption) (err error) {
opts = slices.Concat(r.Options, opts)
opts = append([]option.RequestOption{option.WithHeader("Accept", "*/*"), option.WithRequestBody("application/octet-stream", contents)}, opts...)
if id == "" {
@@ -194,7 +194,7 @@ func (r *BrowserFService) WriteFile(ctx context.Context, id string, contents io.
return
}
path := fmt.Sprintf("browsers/%s/fs/write_file", id)
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, body, nil, opts...)
+ err = requestconfig.ExecuteNewRequest(ctx, http.MethodPut, path, params, nil, opts...)
return
}
diff --git a/internal/apiform/encoder.go b/internal/apiform/encoder.go
index 2002c4b..851e9c0 100644
--- a/internal/apiform/encoder.go
+++ b/internal/apiform/encoder.go
@@ -60,6 +60,7 @@ type encoderField struct {
type encoderEntry struct {
reflect.Type
dateFormat string
+ arrayFmt string
root bool
}
@@ -77,6 +78,7 @@ func (e *encoder) typeEncoder(t reflect.Type) encoderFunc {
entry := encoderEntry{
Type: t,
dateFormat: e.dateFormat,
+ arrayFmt: e.arrayFmt,
root: e.root,
}
@@ -178,34 +180,9 @@ func (e *encoder) newPrimitiveTypeEncoder(t reflect.Type) encoderFunc {
}
}
-func arrayKeyEncoder(arrayFmt string) func(string, int) string {
- var keyFn func(string, int) string
- switch arrayFmt {
- case "comma", "repeat":
- keyFn = func(k string, _ int) string { return k }
- case "brackets":
- keyFn = func(key string, _ int) string { return key + "[]" }
- case "indices:dots":
- keyFn = func(k string, i int) string {
- if k == "" {
- return strconv.Itoa(i)
- }
- return k + "." + strconv.Itoa(i)
- }
- case "indices:brackets":
- keyFn = func(k string, i int) string {
- if k == "" {
- return strconv.Itoa(i)
- }
- return k + "[" + strconv.Itoa(i) + "]"
- }
- }
- return keyFn
-}
-
func (e *encoder) newArrayTypeEncoder(t reflect.Type) encoderFunc {
itemEncoder := e.typeEncoder(t.Elem())
- keyFn := arrayKeyEncoder(e.arrayFmt)
+ keyFn := e.arrayKeyEncoder()
return func(key string, v reflect.Value, writer *multipart.Writer) error {
if keyFn == nil {
return fmt.Errorf("apiform: unsupported array format")
@@ -303,13 +280,10 @@ func (e *encoder) newStructTypeEncoder(t reflect.Type) encoderFunc {
})
return func(key string, value reflect.Value, writer *multipart.Writer) error {
- if key != "" {
- key = key + "."
- }
-
+ keyFn := e.objKeyEncoder(key)
for _, ef := range encoderFields {
field := value.FieldByIndex(ef.idx)
- err := ef.fn(key+ef.tag.name, field, writer)
+ err := ef.fn(keyFn(ef.tag.name), field, writer)
if err != nil {
return err
}
@@ -405,6 +379,43 @@ func (e *encoder) newReaderTypeEncoder() encoderFunc {
}
}
+func (e encoder) arrayKeyEncoder() func(string, int) string {
+ var keyFn func(string, int) string
+ switch e.arrayFmt {
+ case "comma", "repeat":
+ keyFn = func(k string, _ int) string { return k }
+ case "brackets":
+ keyFn = func(key string, _ int) string { return key + "[]" }
+ case "indices:dots":
+ keyFn = func(k string, i int) string {
+ if k == "" {
+ return strconv.Itoa(i)
+ }
+ return k + "." + strconv.Itoa(i)
+ }
+ case "indices:brackets":
+ keyFn = func(k string, i int) string {
+ if k == "" {
+ return strconv.Itoa(i)
+ }
+ return k + "[" + strconv.Itoa(i) + "]"
+ }
+ }
+ return keyFn
+}
+
+func (e encoder) objKeyEncoder(parent string) func(string) string {
+ if parent == "" {
+ return func(child string) string { return child }
+ }
+ switch e.arrayFmt {
+ case "brackets":
+ return func(child string) string { return parent + "[" + child + "]" }
+ default:
+ return func(child string) string { return parent + "." + child }
+ }
+}
+
// Given a []byte of json (may either be an empty object or an object that already contains entries)
// encode all of the entries in the map to the json byte array.
func (e *encoder) encodeMapEntries(key string, v reflect.Value, writer *multipart.Writer) error {
@@ -413,10 +424,6 @@ func (e *encoder) encodeMapEntries(key string, v reflect.Value, writer *multipar
value reflect.Value
}
- if key != "" {
- key = key + "."
- }
-
pairs := []mapPair{}
iter := v.MapRange()
@@ -434,8 +441,9 @@ func (e *encoder) encodeMapEntries(key string, v reflect.Value, writer *multipar
})
elementEncoder := e.typeEncoder(v.Type().Elem())
+ keyFn := e.objKeyEncoder(key)
for _, p := range pairs {
- err := elementEncoder(key+string(p.key), p.value, writer)
+ err := elementEncoder(keyFn(p.key), p.value, writer)
if err != nil {
return err
}
diff --git a/internal/apiform/form_test.go b/internal/apiform/form_test.go
index e91b9ea..5d56066 100644
--- a/internal/apiform/form_test.go
+++ b/internal/apiform/form_test.go
@@ -123,6 +123,18 @@ type StructUnion struct {
param.APIUnion
}
+type MultipartMarshalerParent struct {
+ Middle MultipartMarshalerMiddleNext `form:"middle"`
+}
+
+type MultipartMarshalerMiddleNext struct {
+ MiddleNext MultipartMarshalerMiddle `form:"middleNext"`
+}
+
+type MultipartMarshalerMiddle struct {
+ Child int `form:"child"`
+}
+
var tests = map[string]struct {
buf string
val any
@@ -366,6 +378,19 @@ true
},
},
},
+ "recursive_struct,brackets": {
+ `--xxx
+Content-Disposition: form-data; name="child[name]"
+
+Alex
+--xxx
+Content-Disposition: form-data; name="name"
+
+Robert
+--xxx--
+`,
+ Recursive{Name: "Robert", Child: &Recursive{Name: "Alex"}},
+ },
"recursive_struct": {
`--xxx
@@ -529,6 +554,30 @@ Content-Disposition: form-data; name="union"
Union: UnionTime(time.Date(2010, 05, 23, 0, 0, 0, 0, time.UTC)),
},
},
+ "deeply-nested-struct,brackets": {
+ `--xxx
+Content-Disposition: form-data; name="middle[middleNext][child]"
+
+10
+--xxx--
+`,
+ MultipartMarshalerParent{
+ Middle: MultipartMarshalerMiddleNext{
+ MiddleNext: MultipartMarshalerMiddle{
+ Child: 10,
+ },
+ },
+ },
+ },
+ "deeply-nested-map,brackets": {
+ `--xxx
+Content-Disposition: form-data; name="middle[middleNext][child]"
+
+10
+--xxx--
+`,
+ map[string]any{"middle": map[string]any{"middleNext": map[string]any{"child": 10}}},
+ },
}
func TestEncode(t *testing.T) {
@@ -553,7 +602,7 @@ func TestEncode(t *testing.T) {
}
raw := buf.Bytes()
if string(raw) != strings.ReplaceAll(test.buf, "\n", "\r\n") {
- t.Errorf("expected %+#v to serialize to '%s' but got '%s'", test.val, test.buf, string(raw))
+ t.Errorf("expected %+#v to serialize to '%s' but got '%s' (with format %s)", test.val, test.buf, string(raw), arrayFmt)
}
})
}
diff --git a/internal/version.go b/internal/version.go
index e482b6b..834f803 100644
--- a/internal/version.go
+++ b/internal/version.go
@@ -2,4 +2,4 @@
package internal
-const PackageVersion = "0.22.0" // x-release-please-version
+const PackageVersion = "0.23.0" // x-release-please-version