diff --git a/CHANGELOG.md b/CHANGELOG.md
index 9bb7268..bc95e9b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,31 @@ existing `0.1.0` release; earlier development prereleases are not listed.
## [Unreleased]
+### Added
+
+- Automatically mark direct Forward and Managed Session creation with `__qca_sdk_created`, `__qca_sdk_language`, and the actual `__qca_sdk_version`, preserving caller metadata.
+- Add Forward Dreams (create, list, retrieve, cancel, archive), channel pairing list/retrieve/update, and Managed OAuth start with typed requests and responses.
+- Add Identity automatic memory-store control, mount access and cursor pagination, sparse managed-capability overrides, and full tools-array replacement.
+- Support string Template references and Advisor model entries in Forward Multiagent rosters, Schedule file resources, and optional Run input snapshots.
+- Add typed Managed OSS bucket storage with separate write credentials/read views, and Memory Store ID cursor parameters.
+
+### Fixed
+
+- Align Forward Outcome rubric objects and Managed Agent/Dream model configuration with the official API. Dream model defaults to `auto` when omitted; object configuration supports `effort` and `context_window`.
+
+### Breaking changes
+
+- Session creation rejects conflicting values for the three reserved SDK metadata keys before sending; matching string values remain accepted. Missing or null metadata now contains the markers, which count toward API metadata limits.
+- Forward event `rubric` is a text/content or file/file_id object instead of a string.
+- Managed Agent `effort` is a level string instead of an object; Agent and Dream model configuration no longer declares the unsupported `speed` field.
+- Identity mount `List` now takes `IdentityMemoryStoreListParams` and returns `pagination.Page[MemoryStoreMount]`; supply an empty params struct to preserve an unfiltered call.
+- Wrap Identity tool maps in `IdentityToolsUnionParam{OfOverrides: ...}`; use `OfArray` for replacement. Read maps through `Tools.OfOverrides`.
+
+### Migration
+
+- Rename business fields that collide with the three `__qca_sdk_` keys and leave space for automatic markers. See “SDK-created Session metadata” in the README.
+- See the README's “Official contract alignment” section for updated model/rubric types, pagination calls and explicit null clearing.
+
## [0.12.0]
### Added
diff --git a/README.md b/README.md
index fa03b24..293d917 100644
--- a/README.md
+++ b/README.md
@@ -51,6 +51,32 @@ This SDK is pre-1.0, so pin a version explicitly and keep the version your build
- Go **1.23** or later.
- A PAT or Service Account credential for the target environment, with access to the resources you call. Managed SA access also needs a workspace binding.
+## SDK-created Session metadata
+
+Direct Forward and Managed Session creation automatically adds these string-valued
+metadata fields:
+
+| Field | Value |
+| --- | --- |
+| `__qca_sdk_created` | `"true"` |
+| `__qca_sdk_language` | `"go"` |
+| `__qca_sdk_version` | The installed SDK's version |
+
+Reserve the `__qca_sdk_` prefix for SDK provenance. Business metadata is preserved,
+and the caller's metadata object is not mutated. Omitted or null metadata becomes
+an object containing the markers. Passing an existing marker with the exact same
+string value is accepted; a different value or type (including null) fails locally
+before any HTTP request. This also applies after request body/JSON options are merged.
+
+Session updates, reads and event operations do not inject or repair these fields.
+Sessions created indirectly through Schedules, Batches or Realtime are outside this
+behavior. These markers describe the creating SDK; they are client-supplied metadata,
+not an authentication or authorization mechanism.
+
+Migration: rename any business fields that already use these three keys before
+upgrading. Automatic markers count toward API metadata limits; the SDK never drops
+business fields to make room. No additional parameters or opt-in are required.
+
## Usage
The complete program below reads a PAT from the environment, connects to the CN environment and lists the models enabled for the account.
@@ -1232,3 +1258,74 @@ sessions, err := managedClient.Sessions.Search(ctx, managed.SessionSearchParams{
Each resource exposes `Search` for a page and `SearchAutoPaging` for iteration.
Use the page's `GetNextPage()` for manual pagination.
+
+## Official contract alignment
+
+The next release aligns these public types with the official API documentation
+retrieved on 2026-10-27. It introduces source changes relative to 0.12.0:
+Outcome `rubric` is an object; Managed Agent `effort` is a string; Managed Agent
+and Dream model objects do not accept `speed`. Managed Dream `model` is optional
+and defaults to `auto`. Discover model IDs and supported efforts/context windows
+with List models. These Managed model changes do not remove Forward model features.
+
+```go
+rubric := forward.OutcomeRubricParam{Type: "text", Content: forward.String("report exists")}
+model := managed.ManagedAgentsModelConfigParams{ID: "ultimate", Effort: managed.String("high")}
+// Dream model can be omitted; its default is auto.
+dream, err := client.Dreams.New(ctx, forward.DreamNewParams{
+ Inputs: []forward.DreamInputParam{{Type: "identity_template",
+ IdentityID: forward.String("idn_..."), TemplateID: forward.String("tmpl_...")}},
+})
+```
+
+Mount list callers must supply query params, even if empty. The result now uses
+the standard page type. Use `ListAutoPaging` to traverse every page:
+
+```go
+pager := client.Identities.MemoryStores.ListAutoPaging(ctx, "idn_...", "tmpl_...",
+ forward.IdentityMemoryStoreListParams{Limit: forward.Int(20)})
+for pager.Next() {
+ fmt.Println(pager.Current().MemoryStoreID)
+}
+if err := pager.Err(); err != nil { /* handle error */ }
+```
+
+Identity tool maps now use `IdentityToolsUnionParam{OfOverrides: toolMap}`;
+`OfArray: []forward.ToolParam{}` explicitly replaces all tools with an empty list.
+Use `param.NullStruct[forward.IdentityToolsUnionParam]()` to restore inherited
+tools, and `param.NullMap[map[string]forward.ManagedCapabilityOverrideParam]()`
+to clear all managed-capability overrides. A selector value of
+`param.NullStruct[forward.ManagedCapabilityOverrideParam]()` clears that selector.
+For roster string entries use `MultiagentEntryParam{OfString: forward.String("tmpl_...")}`;
+Advisor entries use `Type: "advisor", Model: forward.String("ultimate")`.
+
+New Forward Dream calls require a PAT or an admin SAT; an Identity SAT is not
+supported. Inputs contain exactly one primary Memory Store or Identity/Template
+source, optionally plus Session sources. Pairing `update` changes an active
+binding; supply at least one nonempty Identity or Template ID. Use pairing
+`create` to complete a pending pairing. Pending records preserve empty
+`identity_id`, `template_id`, and `paired_at` strings.
+
+Identity `auto_memory_store=false` disables automatic default-store creation.
+Independent mounts now accept `access="read_write"`; omit access for a new
+read-only mount, or to preserve an existing mount's permission. Schedule
+`resources` accepts file entries and `[]` clears them; Run retrieval supports
+`include_initial_events=true` to return the saved input snapshot.
+
+Managed cloud Environment `config.storage.buckets` supports up to eight OSS
+mounts. When the resulting configuration has buckets, explicitly include beta
+`oss-bucket-2026-09-23` (`Betas` in Go, `betas` in Python/TS). Send credentials
+only when creating or replacing them; omit `credential` on an existing named
+bucket to keep it. Responses expose a read view without role ARN or AccessKey
+secret. `storage: {buckets: []}` clears mounts.
+
+Managed `OAuth.Start` (Go) / `oauth.start` (Python/TS) returns `authorization_url`,
+`state`, and `callback_origin`; the user completes authorization in a browser.
+Client secrets go in the POST body, never in a URL. This method does not open a
+browser or complete consent automatically.
+
+See the official [Outcome contract](https://docs.qoder.com/cloud-agents/api/forward/sessions/send-events),
+[Identity overrides](https://docs.qoder.com/cloud-agents/api/forward/identities/upsert-config),
+[Dream inputs](https://docs.qoder.com/cloud-agents/api/forward/dreams/create),
+[OSS storage](https://docs.qoder.com/cloud-agents/api/environments/storage-buckets),
+and [OAuth flow](https://docs.qoder.com/cloud-agents/api/vaults/start-oauth).
diff --git a/convention/session_metadata.go b/convention/session_metadata.go
new file mode 100644
index 0000000..ac49101
--- /dev/null
+++ b/convention/session_metadata.go
@@ -0,0 +1,62 @@
+package convention
+
+import (
+ "bytes"
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+)
+
+// ExecuteNewSessionRequest adds SDK provenance to a Session creation request
+// after request options have been applied. Conflicting reserved metadata fails
+// before transport; caller-owned params and metadata are never modified.
+func ExecuteNewSessionRequest(ctx context.Context, method string, u string, body any, dst any, opts ...RequestOption) error {
+ cfg, err := NewRequestConfig(ctx, method, u, body, dst, opts...)
+ if err != nil {
+ return err
+ }
+ if cfg.Body == nil {
+ return fmt.Errorf("session creation body must be a JSON object")
+ }
+ if closer, ok := cfg.Body.(io.Closer); ok {
+ defer closer.Close()
+ }
+ data, err := io.ReadAll(cfg.Body)
+ if err != nil {
+ return err
+ }
+ var payload map[string]json.RawMessage
+ if err := json.Unmarshal(data, &payload); err != nil || payload == nil {
+ return fmt.Errorf("session creation body must be a JSON object")
+ }
+ metadata := map[string]json.RawMessage{}
+ if raw, ok := payload["metadata"]; ok && !bytes.Equal(bytes.TrimSpace(raw), []byte("null")) {
+ if err := json.Unmarshal(raw, &metadata); err != nil {
+ return fmt.Errorf("session creation metadata must be a JSON object or null")
+ }
+ }
+ for _, field := range []struct{ key, value string }{
+ {"__qca_sdk_created", "true"},
+ {"__qca_sdk_language", "go"},
+ {"__qca_sdk_version", packageVersion},
+ } {
+ if raw, ok := metadata[field.key]; ok {
+ var value string
+ if err := json.Unmarshal(raw, &value); err != nil || value != field.value {
+ return fmt.Errorf("conflicting SDK metadata field: %s", field.key)
+ }
+ }
+ metadata[field.key], _ = json.Marshal(field.value)
+ }
+ payload["metadata"], err = json.Marshal(metadata)
+ if err != nil {
+ return err
+ }
+ data, err = json.Marshal(payload)
+ if err != nil {
+ return err
+ }
+ cfg.Body = bytes.NewBuffer(data)
+ return cfg.Execute()
+}
diff --git a/convention/session_metadata_test.go b/convention/session_metadata_test.go
new file mode 100644
index 0000000..b5dd1b1
--- /dev/null
+++ b/convention/session_metadata_test.go
@@ -0,0 +1,206 @@
+package convention_test
+
+import (
+ "context"
+ "encoding/json"
+ "io"
+ "maps"
+ "net/http"
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/option"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/managed"
+)
+
+func createMarkedSession(mode string, opts []option.RequestOption, forwardMetadata map[string]any, managedMetadata map[string]string) error {
+ if mode == "forward" {
+ c := forward.NewClient(opts...)
+ _, err := c.Sessions.New(context.Background(), forward.SessionNewParams{IdentityID: "idn", TemplateID: "tmpl", Metadata: forwardMetadata})
+ return err
+ }
+ c := managed.NewClient(opts...)
+ _, err := c.Sessions.New(context.Background(), managed.SessionNewParams{Metadata: managedMetadata})
+ return err
+}
+
+func TestSessionCreationMetadata(t *testing.T) {
+ for _, mode := range []string{"forward", "managed"} {
+ for _, populated := range []bool{false, true} {
+ t.Run(mode+map[bool]string{false: "/omitted", true: "/business"}[populated], func(t *testing.T) {
+ var f map[string]any
+ var m map[string]string
+ if populated {
+ f = map[string]any{"ticket": "A-123", "nested": map[string]any{"count": int64(9007199254740993)}}
+ m = map[string]string{"ticket": "A-123"}
+ }
+ beforeF, beforeM := maps.Clone(f), maps.Clone(m)
+ calls := 0
+ var sentMetadata map[string]string
+ opts := append(requestOptions(func(r *http.Request) (*http.Response, error) {
+ calls++
+ if r.Method != "POST" || !strings.HasSuffix(r.URL.Path, "/sessions") {
+ t.Fatalf("unexpected request: %s %s", r.Method, r.URL)
+ }
+ var body struct {
+ Metadata map[string]json.RawMessage `json:"metadata"`
+ }
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ t.Fatal(err)
+ }
+ want := map[string]string{"__qca_sdk_created": "true", "__qca_sdk_language": "go", "__qca_sdk_version": strings.TrimPrefix(r.Header.Get("User-Agent"), "qca-go/")}
+ for key, expected := range want {
+ var got string
+ if err := json.Unmarshal(body.Metadata[key], &got); err != nil || got != expected || got == "" {
+ t.Fatalf("%s: %s, want %q", key, body.Metadata[key], expected)
+ }
+ }
+ if populated && string(body.Metadata["ticket"]) != `"A-123"` {
+ t.Fatal(body.Metadata)
+ }
+ if populated && mode == "forward" && string(body.Metadata["nested"]) != `{"count":9007199254740993}` {
+ t.Fatal("business metadata changed", body.Metadata)
+ }
+ sentMetadata = want
+ return &http.Response{StatusCode: 200, Header: http.Header{"Content-Type": {"application/json"}}, Body: io.NopCloser(strings.NewReader(`{"id":"sess_test"}`))}, nil
+ }), option.WithPAT("test"), option.WithHeader("X-Qoder-Package-Version", "custom-header"))
+ for range 2 {
+ if err := createMarkedSession(mode, opts, f, m); err != nil {
+ t.Fatal(err)
+ }
+ }
+ if !reflect.DeepEqual(f, beforeF) || !reflect.DeepEqual(m, beforeM) {
+ t.Fatal("caller metadata mutated")
+ }
+ // Reusing exactly matching markers is accepted.
+ extra := append(opts, option.WithJSONSet("metadata", sentMetadata))
+ if populated {
+ extra = append(extra, option.WithJSONSet("metadata.ticket", "A-123"))
+ if mode == "forward" {
+ extra = append(extra, option.WithJSONSet("metadata.nested", f["nested"]))
+ }
+ }
+ if err := createMarkedSession(mode, extra, nil, nil); err != nil {
+ t.Fatal(err)
+ }
+ if calls != 3 {
+ t.Fatal(calls)
+ }
+ })
+ }
+ }
+}
+
+func TestSessionMetadataConflictsBeforeTransport(t *testing.T) {
+ for _, mode := range []string{"forward", "managed"} {
+ for _, key := range []string{"__qca_sdk_created", "__qca_sdk_language", "__qca_sdk_version"} {
+ for _, value := range []any{"user-value", nil, true, 12} {
+ t.Run(mode+"/"+key+"/"+string(mustJSON(t, value)), func(t *testing.T) {
+ calls := 0
+ opts := append(requestOptions(func(r *http.Request) (*http.Response, error) {
+ calls++
+ t.Fatal("conflict reached transport")
+ return nil, nil
+ }), option.WithPAT("test"))
+ metadata := map[string]any{key: value}
+ for _, override := range []option.RequestOption{
+ option.WithJSONSet("metadata", metadata),
+ option.WithRequestBody("application/json", mustJSON(t, map[string]any{"metadata": metadata})),
+ } {
+ err := createMarkedSession(mode, append(opts, override), nil, nil)
+ if err == nil || err.Error() != "conflicting SDK metadata field: "+key {
+ t.Fatalf("wrong error: %v", err)
+ }
+ }
+ if mode == "forward" {
+ if err := createMarkedSession(mode, opts, metadata, nil); err == nil {
+ t.Fatal("typed conflict accepted")
+ }
+ } else if s, ok := value.(string); ok {
+ if err := createMarkedSession(mode, opts, nil, map[string]string{key: s}); err == nil {
+ t.Fatal("typed conflict accepted")
+ }
+ }
+ if calls != 0 || !reflect.DeepEqual(metadata, map[string]any{key: value}) {
+ t.Fatal("unexpected mutation or request")
+ }
+ })
+ }
+ }
+ }
+}
+
+func mustJSON(t *testing.T, value any) []byte {
+ t.Helper()
+ b, err := json.Marshal(value)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return b
+}
+
+func TestSessionMetadataRawBody(t *testing.T) {
+ for _, mode := range []string{"forward", "managed"} {
+ for _, raw := range []string{`{}`, `{"metadata":null}`, `{"metadata":{}}`, `{"metadata":{"__qca_sdk_future":"preserved"}}`} {
+ calls := 0
+ opts := append(requestOptions(func(r *http.Request) (*http.Response, error) {
+ calls++
+ var body map[string]map[string]string
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ t.Fatal(err)
+ }
+ if body["metadata"]["__qca_sdk_created"] != "true" {
+ t.Fatal(body)
+ }
+ if strings.Contains(raw, "future") && body["metadata"]["__qca_sdk_future"] != "preserved" {
+ t.Fatal(body)
+ }
+ return &http.Response{StatusCode: 200, Header: http.Header{"Content-Type": {"application/json"}}, Body: io.NopCloser(strings.NewReader(`{}`))}, nil
+ }), option.WithPAT("test"))
+ reader := &trackedBody{Reader: strings.NewReader(raw)}
+ if err := createMarkedSession(mode, append(opts, option.WithRequestBody("application/json", reader)), nil, nil); err != nil {
+ t.Fatal(err)
+ }
+ if calls != 1 || reader.closes != 1 {
+ t.Fatalf("calls %d, closes %d", calls, reader.closes)
+ }
+ }
+ for _, raw := range []string{`null`, `[]`, `invalid`, `{"metadata":[]}`, `{"metadata":false}`, `{"metadata":"invalid"}`} {
+ opts := append(requestOptions(func(r *http.Request) (*http.Response, error) {
+ t.Fatal("invalid metadata reached transport")
+ return nil, nil
+ }), option.WithPAT("test"), option.WithRequestBody("application/json", strings.NewReader(raw)))
+ if err := createMarkedSession(mode, opts, nil, nil); err == nil {
+ t.Fatal("invalid body accepted:", raw)
+ }
+ }
+ }
+}
+
+func TestSessionUpdateDoesNotStampMetadata(t *testing.T) {
+ for _, mode := range []string{"forward", "managed"} {
+ opts := append(requestOptions(func(r *http.Request) (*http.Response, error) {
+ var body map[string]any
+ if err := json.NewDecoder(r.Body).Decode(&body); err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(body, map[string]any{"metadata": map[string]any{"__qca_sdk_language": "historic"}}) {
+ t.Fatal(body)
+ }
+ return &http.Response{StatusCode: 200, Header: http.Header{"Content-Type": {"application/json"}}, Body: io.NopCloser(strings.NewReader(`{}`))}, nil
+ }), option.WithPAT("test"))
+ if mode == "forward" {
+ c := forward.NewClient(opts...)
+ if _, err := c.Sessions.Update(context.Background(), "sess_test", forward.SessionUpdateParams{Metadata: map[string]any{"__qca_sdk_language": "historic"}}); err != nil {
+ t.Fatal(err)
+ }
+ } else {
+ c := managed.NewClient(opts...)
+ if _, err := c.Sessions.Update(context.Background(), "sess_test", managed.SessionUpdateParams{Metadata: map[string]any{"__qca_sdk_language": "historic"}}); err != nil {
+ t.Fatal(err)
+ }
+ }
+ }
+}
diff --git a/docs/api/reference.md b/docs/api/reference.md
index 11d28f2..4944ff0 100644
--- a/docs/api/reference.md
+++ b/docs/api/reference.md
@@ -82,13 +82,22 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [type ChannelPairing](<#ChannelPairing>)
- [func \(r ChannelPairing\) RawJSON\(\) string](<#ChannelPairing.RawJSON>)
- [func \(r \*ChannelPairing\) UnmarshalJSON\(data \[\]byte\) error](<#ChannelPairing.UnmarshalJSON>)
+- [type ChannelPairingListParams](<#ChannelPairingListParams>)
+ - [func \(r ChannelPairingListParams\) URLQuery\(\) \(url.Values, error\)](<#ChannelPairingListParams.URLQuery>)
- [type ChannelPairingNewParams](<#ChannelPairingNewParams>)
- [func \(r ChannelPairingNewParams\) MarshalJSON\(\) \(\[\]byte, error\)](<#ChannelPairingNewParams.MarshalJSON>)
- [func \(r \*ChannelPairingNewParams\) UnmarshalJSON\(data \[\]byte\) error](<#ChannelPairingNewParams.UnmarshalJSON>)
- [type ChannelPairingService](<#ChannelPairingService>)
- [func NewChannelPairingService\(opts ...option.RequestOption\) ChannelPairingService](<#NewChannelPairingService>)
- [func \(r \*ChannelPairingService\) Delete\(ctx context.Context, pairingID string, opts ...option.RequestOption\) \(res \*DeletedChannelPairing, err error\)](<#ChannelPairingService.Delete>)
+ - [func \(r \*ChannelPairingService\) Get\(ctx context.Context, pairingID string, opts ...option.RequestOption\) \(res \*ChannelPairing, err error\)](<#ChannelPairingService.Get>)
+ - [func \(r \*ChannelPairingService\) List\(ctx context.Context, params ChannelPairingListParams, opts ...option.RequestOption\) \(res \*pagination.Page\[ChannelPairing\], err error\)](<#ChannelPairingService.List>)
+ - [func \(r \*ChannelPairingService\) ListAutoPaging\(ctx context.Context, params ChannelPairingListParams, opts ...option.RequestOption\) \*pagination.PageAutoPager\[ChannelPairing\]](<#ChannelPairingService.ListAutoPaging>)
- [func \(r \*ChannelPairingService\) New\(ctx context.Context, params ChannelPairingNewParams, opts ...option.RequestOption\) \(res \*ChannelPairing, err error\)](<#ChannelPairingService.New>)
+ - [func \(r \*ChannelPairingService\) Update\(ctx context.Context, pairingID string, params ChannelPairingUpdateParams, opts ...option.RequestOption\) \(res \*ChannelPairing, err error\)](<#ChannelPairingService.Update>)
+- [type ChannelPairingUpdateParams](<#ChannelPairingUpdateParams>)
+ - [func \(r ChannelPairingUpdateParams\) MarshalJSON\(\) \(\[\]byte, error\)](<#ChannelPairingUpdateParams.MarshalJSON>)
+ - [func \(r \*ChannelPairingUpdateParams\) UnmarshalJSON\(data \[\]byte\) error](<#ChannelPairingUpdateParams.UnmarshalJSON>)
- [type ChannelQRSession](<#ChannelQRSession>)
- [func \(r ChannelQRSession\) RawJSON\(\) string](<#ChannelQRSession.RawJSON>)
- [func \(r \*ChannelQRSession\) UnmarshalJSON\(data \[\]byte\) error](<#ChannelQRSession.UnmarshalJSON>)
@@ -179,6 +188,46 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [type DeletedSkillVersion](<#DeletedSkillVersion>)
- [func \(r DeletedSkillVersion\) RawJSON\(\) string](<#DeletedSkillVersion.RawJSON>)
- [func \(r \*DeletedSkillVersion\) UnmarshalJSON\(data \[\]byte\) error](<#DeletedSkillVersion.UnmarshalJSON>)
+- [type Dream](<#Dream>)
+ - [func \(r Dream\) RawJSON\(\) string](<#Dream.RawJSON>)
+ - [func \(r \*Dream\) UnmarshalJSON\(data \[\]byte\) error](<#Dream.UnmarshalJSON>)
+- [type DreamError](<#DreamError>)
+ - [func \(r DreamError\) RawJSON\(\) string](<#DreamError.RawJSON>)
+ - [func \(r \*DreamError\) UnmarshalJSON\(data \[\]byte\) error](<#DreamError.UnmarshalJSON>)
+- [type DreamInput](<#DreamInput>)
+ - [func \(r DreamInput\) RawJSON\(\) string](<#DreamInput.RawJSON>)
+ - [func \(r \*DreamInput\) UnmarshalJSON\(data \[\]byte\) error](<#DreamInput.UnmarshalJSON>)
+- [type DreamInputParam](<#DreamInputParam>)
+ - [func \(r DreamInputParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#DreamInputParam.MarshalJSON>)
+ - [func \(r \*DreamInputParam\) UnmarshalJSON\(data \[\]byte\) error](<#DreamInputParam.UnmarshalJSON>)
+- [type DreamListParams](<#DreamListParams>)
+ - [func \(r DreamListParams\) URLQuery\(\) \(url.Values, error\)](<#DreamListParams.URLQuery>)
+- [type DreamModelConfig](<#DreamModelConfig>)
+ - [func \(r DreamModelConfig\) RawJSON\(\) string](<#DreamModelConfig.RawJSON>)
+ - [func \(r \*DreamModelConfig\) UnmarshalJSON\(data \[\]byte\) error](<#DreamModelConfig.UnmarshalJSON>)
+- [type DreamModelConfigParam](<#DreamModelConfigParam>)
+ - [func \(r DreamModelConfigParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#DreamModelConfigParam.MarshalJSON>)
+ - [func \(r \*DreamModelConfigParam\) UnmarshalJSON\(data \[\]byte\) error](<#DreamModelConfigParam.UnmarshalJSON>)
+- [type DreamNewParams](<#DreamNewParams>)
+ - [func \(r DreamNewParams\) MarshalJSON\(\) \(\[\]byte, error\)](<#DreamNewParams.MarshalJSON>)
+ - [func \(r \*DreamNewParams\) UnmarshalJSON\(data \[\]byte\) error](<#DreamNewParams.UnmarshalJSON>)
+- [type DreamNewParamsModelUnion](<#DreamNewParamsModelUnion>)
+ - [func \(r DreamNewParamsModelUnion\) MarshalJSON\(\) \(\[\]byte, error\)](<#DreamNewParamsModelUnion.MarshalJSON>)
+ - [func \(r \*DreamNewParamsModelUnion\) UnmarshalJSON\(data \[\]byte\) error](<#DreamNewParamsModelUnion.UnmarshalJSON>)
+- [type DreamOutput](<#DreamOutput>)
+ - [func \(r DreamOutput\) RawJSON\(\) string](<#DreamOutput.RawJSON>)
+ - [func \(r \*DreamOutput\) UnmarshalJSON\(data \[\]byte\) error](<#DreamOutput.UnmarshalJSON>)
+- [type DreamService](<#DreamService>)
+ - [func NewDreamService\(opts ...option.RequestOption\) DreamService](<#NewDreamService>)
+ - [func \(r \*DreamService\) Archive\(ctx context.Context, dreamID string, opts ...option.RequestOption\) \(res \*Dream, err error\)](<#DreamService.Archive>)
+ - [func \(r \*DreamService\) Cancel\(ctx context.Context, dreamID string, opts ...option.RequestOption\) \(res \*Dream, err error\)](<#DreamService.Cancel>)
+ - [func \(r \*DreamService\) Get\(ctx context.Context, dreamID string, opts ...option.RequestOption\) \(res \*Dream, err error\)](<#DreamService.Get>)
+ - [func \(r \*DreamService\) List\(ctx context.Context, params DreamListParams, opts ...option.RequestOption\) \(res \*pagination.Page\[Dream\], err error\)](<#DreamService.List>)
+ - [func \(r \*DreamService\) ListAutoPaging\(ctx context.Context, params DreamListParams, opts ...option.RequestOption\) \*pagination.PageAutoPager\[Dream\]](<#DreamService.ListAutoPaging>)
+ - [func \(r \*DreamService\) New\(ctx context.Context, params DreamNewParams, opts ...option.RequestOption\) \(res \*Dream, err error\)](<#DreamService.New>)
+- [type DreamUsage](<#DreamUsage>)
+ - [func \(r DreamUsage\) RawJSON\(\) string](<#DreamUsage.RawJSON>)
+ - [func \(r \*DreamUsage\) UnmarshalJSON\(data \[\]byte\) error](<#DreamUsage.UnmarshalJSON>)
- [type DriveClearParams](<#DriveClearParams>)
- [func \(r DriveClearParams\) URLQuery\(\) \(url.Values, error\)](<#DriveClearParams.URLQuery>)
- [func \(r \*DriveClearParams\) UnmarshalJSON\(data \[\]byte\) error](<#DriveClearParams.UnmarshalJSON>)
@@ -359,6 +408,8 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [type IdentityListTemplatesResponse](<#IdentityListTemplatesResponse>)
- [func \(r IdentityListTemplatesResponse\) RawJSON\(\) string](<#IdentityListTemplatesResponse.RawJSON>)
- [func \(r \*IdentityListTemplatesResponse\) UnmarshalJSON\(data \[\]byte\) error](<#IdentityListTemplatesResponse.UnmarshalJSON>)
+- [type IdentityMemoryStoreListParams](<#IdentityMemoryStoreListParams>)
+ - [func \(r IdentityMemoryStoreListParams\) URLQuery\(\) \(url.Values, error\)](<#IdentityMemoryStoreListParams.URLQuery>)
- [type IdentityMemoryStoreListResponse](<#IdentityMemoryStoreListResponse>)
- [func \(r IdentityMemoryStoreListResponse\) RawJSON\(\) string](<#IdentityMemoryStoreListResponse.RawJSON>)
- [func \(r \*IdentityMemoryStoreListResponse\) UnmarshalJSON\(data \[\]byte\) error](<#IdentityMemoryStoreListResponse.UnmarshalJSON>)
@@ -368,7 +419,8 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [type IdentityMemoryStoreService](<#IdentityMemoryStoreService>)
- [func NewIdentityMemoryStoreService\(opts ...option.RequestOption\) IdentityMemoryStoreService](<#NewIdentityMemoryStoreService>)
- [func \(r \*IdentityMemoryStoreService\) Detach\(ctx context.Context, identityID string, templateID string, memoryStoreID string, opts ...option.RequestOption\) \(res \*DeletedMemoryStoreMount, err error\)](<#IdentityMemoryStoreService.Detach>)
- - [func \(r \*IdentityMemoryStoreService\) List\(ctx context.Context, identityID string, templateID string, opts ...option.RequestOption\) \(res \*IdentityMemoryStoreListResponse, err error\)](<#IdentityMemoryStoreService.List>)
+ - [func \(r \*IdentityMemoryStoreService\) List\(ctx context.Context, identityID string, templateID string, params IdentityMemoryStoreListParams, opts ...option.RequestOption\) \(res \*pagination.Page\[MemoryStoreMount\], err error\)](<#IdentityMemoryStoreService.List>)
+ - [func \(r \*IdentityMemoryStoreService\) ListAutoPaging\(ctx context.Context, identityID, templateID string, params IdentityMemoryStoreListParams, opts ...option.RequestOption\) \*pagination.PageAutoPager\[MemoryStoreMount\]](<#IdentityMemoryStoreService.ListAutoPaging>)
- [func \(r \*IdentityMemoryStoreService\) Mount\(ctx context.Context, identityID string, templateID string, params IdentityMemoryStoreMountParams, opts ...option.RequestOption\) \(res \*MemoryStoreMount, err error\)](<#IdentityMemoryStoreService.Mount>)
- [type IdentityNewParams](<#IdentityNewParams>)
- [func \(r IdentityNewParams\) MarshalJSON\(\) \(\[\]byte, error\)](<#IdentityNewParams.MarshalJSON>)
@@ -396,6 +448,12 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [type IdentityTemplate](<#IdentityTemplate>)
- [func \(r IdentityTemplate\) RawJSON\(\) string](<#IdentityTemplate.RawJSON>)
- [func \(r \*IdentityTemplate\) UnmarshalJSON\(data \[\]byte\) error](<#IdentityTemplate.UnmarshalJSON>)
+- [type IdentityToolsUnion](<#IdentityToolsUnion>)
+ - [func \(r IdentityToolsUnion\) RawJSON\(\) string](<#IdentityToolsUnion.RawJSON>)
+ - [func \(r \*IdentityToolsUnion\) UnmarshalJSON\(data \[\]byte\) error](<#IdentityToolsUnion.UnmarshalJSON>)
+- [type IdentityToolsUnionParam](<#IdentityToolsUnionParam>)
+ - [func \(r IdentityToolsUnionParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#IdentityToolsUnionParam.MarshalJSON>)
+ - [func \(r \*IdentityToolsUnionParam\) UnmarshalJSON\(data \[\]byte\) error](<#IdentityToolsUnionParam.UnmarshalJSON>)
- [type IdentityUpdateParams](<#IdentityUpdateParams>)
- [func \(r IdentityUpdateParams\) MarshalJSON\(\) \(\[\]byte, error\)](<#IdentityUpdateParams.MarshalJSON>)
- [func \(r \*IdentityUpdateParams\) UnmarshalJSON\(data \[\]byte\) error](<#IdentityUpdateParams.UnmarshalJSON>)
@@ -426,6 +484,12 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [type MCPServerParam](<#MCPServerParam>)
- [func \(r MCPServerParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#MCPServerParam.MarshalJSON>)
- [func \(r \*MCPServerParam\) UnmarshalJSON\(data \[\]byte\) error](<#MCPServerParam.UnmarshalJSON>)
+- [type ManagedCapabilityOverride](<#ManagedCapabilityOverride>)
+ - [func \(r ManagedCapabilityOverride\) RawJSON\(\) string](<#ManagedCapabilityOverride.RawJSON>)
+ - [func \(r \*ManagedCapabilityOverride\) UnmarshalJSON\(data \[\]byte\) error](<#ManagedCapabilityOverride.UnmarshalJSON>)
+- [type ManagedCapabilityOverrideParam](<#ManagedCapabilityOverrideParam>)
+ - [func \(r ManagedCapabilityOverrideParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#ManagedCapabilityOverrideParam.MarshalJSON>)
+ - [func \(r \*ManagedCapabilityOverrideParam\) UnmarshalJSON\(data \[\]byte\) error](<#ManagedCapabilityOverrideParam.UnmarshalJSON>)
- [type ManagedToolConfig](<#ManagedToolConfig>)
- [func \(r ManagedToolConfig\) RawJSON\(\) string](<#ManagedToolConfig.RawJSON>)
- [func \(r \*ManagedToolConfig\) UnmarshalJSON\(data \[\]byte\) error](<#ManagedToolConfig.UnmarshalJSON>)
@@ -514,10 +578,18 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [func \(r \*MultiagentConfigParam\) UnmarshalJSON\(data \[\]byte\) error](<#MultiagentConfigParam.UnmarshalJSON>)
- [type MultiagentEntry](<#MultiagentEntry>)
- [func \(r MultiagentEntry\) RawJSON\(\) string](<#MultiagentEntry.RawJSON>)
+ - [func \(r \*MultiagentEntry\) UnmarshalAPIJSON\(data \[\]byte\) error](<#MultiagentEntry.UnmarshalAPIJSON>)
- [func \(r \*MultiagentEntry\) UnmarshalJSON\(data \[\]byte\) error](<#MultiagentEntry.UnmarshalJSON>)
- [type MultiagentEntryParam](<#MultiagentEntryParam>)
- [func \(r MultiagentEntryParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#MultiagentEntryParam.MarshalJSON>)
+ - [func \(r \*MultiagentEntryParam\) UnmarshalAPIJSON\(data \[\]byte\) error](<#MultiagentEntryParam.UnmarshalAPIJSON>)
- [func \(r \*MultiagentEntryParam\) UnmarshalJSON\(data \[\]byte\) error](<#MultiagentEntryParam.UnmarshalJSON>)
+- [type OutcomeRubric](<#OutcomeRubric>)
+ - [func \(r OutcomeRubric\) RawJSON\(\) string](<#OutcomeRubric.RawJSON>)
+ - [func \(r \*OutcomeRubric\) UnmarshalJSON\(data \[\]byte\) error](<#OutcomeRubric.UnmarshalJSON>)
+- [type OutcomeRubricParam](<#OutcomeRubricParam>)
+ - [func \(r OutcomeRubricParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#OutcomeRubricParam.MarshalJSON>)
+ - [func \(r \*OutcomeRubricParam\) UnmarshalJSON\(data \[\]byte\) error](<#OutcomeRubricParam.UnmarshalJSON>)
- [type PermissionPolicy](<#PermissionPolicy>)
- [func \(r PermissionPolicy\) RawJSON\(\) string](<#PermissionPolicy.RawJSON>)
- [func \(r \*PermissionPolicy\) UnmarshalJSON\(data \[\]byte\) error](<#PermissionPolicy.UnmarshalJSON>)
@@ -627,6 +699,12 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [type ScheduleExecution](<#ScheduleExecution>)
- [func \(r ScheduleExecution\) RawJSON\(\) string](<#ScheduleExecution.RawJSON>)
- [func \(r \*ScheduleExecution\) UnmarshalJSON\(data \[\]byte\) error](<#ScheduleExecution.UnmarshalJSON>)
+- [type ScheduleFileResource](<#ScheduleFileResource>)
+ - [func \(r ScheduleFileResource\) RawJSON\(\) string](<#ScheduleFileResource.RawJSON>)
+ - [func \(r \*ScheduleFileResource\) UnmarshalJSON\(data \[\]byte\) error](<#ScheduleFileResource.UnmarshalJSON>)
+- [type ScheduleFileResourceParam](<#ScheduleFileResourceParam>)
+ - [func \(r ScheduleFileResourceParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#ScheduleFileResourceParam.MarshalJSON>)
+ - [func \(r \*ScheduleFileResourceParam\) UnmarshalJSON\(data \[\]byte\) error](<#ScheduleFileResourceParam.UnmarshalJSON>)
- [type ScheduleInitialEventsItem](<#ScheduleInitialEventsItem>)
- [func \(r ScheduleInitialEventsItem\) RawJSON\(\) string](<#ScheduleInitialEventsItem.RawJSON>)
- [func \(r \*ScheduleInitialEventsItem\) UnmarshalJSON\(data \[\]byte\) error](<#ScheduleInitialEventsItem.UnmarshalJSON>)
@@ -2031,6 +2109,35 @@ func (r *ChannelPairing) UnmarshalJSON(data []byte) error
+
+## type [ChannelPairingListParams]()
+
+
+
+```go
+type ChannelPairingListParams struct {
+ ChannelID param.Opt[string] `query:"channel_id,omitzero" json:"-"`
+ Status param.Opt[string] `query:"status,omitzero" json:"-"`
+ TargetType param.Opt[string] `query:"target_type,omitzero" json:"-"`
+ TargetExternalID param.Opt[string] `query:"target_external_id,omitzero" json:"-"`
+ IdentityID param.Opt[string] `query:"identity_id,omitzero" json:"-"`
+ TemplateID param.Opt[string] `query:"template_id,omitzero" json:"-"`
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
+ BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(ChannelPairingListParams\) [URLQuery]()
+
+```go
+func (r ChannelPairingListParams) URLQuery() (url.Values, error)
+```
+
+
+
## type [ChannelPairingNewParams]()
@@ -2100,6 +2207,33 @@ func (r *ChannelPairingService) Delete(ctx context.Context, pairingID string, op
Remove Channel pairing
+
+### func \(\*ChannelPairingService\) [Get]()
+
+```go
+func (r *ChannelPairingService) Get(ctx context.Context, pairingID string, opts ...option.RequestOption) (res *ChannelPairing, err error)
+```
+
+
+
+
+### func \(\*ChannelPairingService\) [List]()
+
+```go
+func (r *ChannelPairingService) List(ctx context.Context, params ChannelPairingListParams, opts ...option.RequestOption) (res *pagination.Page[ChannelPairing], err error)
+```
+
+
+
+
+### func \(\*ChannelPairingService\) [ListAutoPaging]()
+
+```go
+func (r *ChannelPairingService) ListAutoPaging(ctx context.Context, params ChannelPairingListParams, opts ...option.RequestOption) *pagination.PageAutoPager[ChannelPairing]
+```
+
+
+
### func \(\*ChannelPairingService\) [New]()
@@ -2109,6 +2243,46 @@ func (r *ChannelPairingService) New(ctx context.Context, params ChannelPairingNe
Complete Channel pairing
+
+### func \(\*ChannelPairingService\) [Update]()
+
+```go
+func (r *ChannelPairingService) Update(ctx context.Context, pairingID string, params ChannelPairingUpdateParams, opts ...option.RequestOption) (res *ChannelPairing, err error)
+```
+
+Update changes an active binding. Supply at least one nonempty field.
+
+
+## type [ChannelPairingUpdateParams]()
+
+
+
+```go
+type ChannelPairingUpdateParams struct {
+ IdentityID param.Opt[string] `json:"identity_id,omitzero"`
+ TemplateID param.Opt[string] `json:"template_id,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(ChannelPairingUpdateParams\) [MarshalJSON]()
+
+```go
+func (r ChannelPairingUpdateParams) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*ChannelPairingUpdateParams\) [UnmarshalJSON]()
+
+```go
+func (r *ChannelPairingUpdateParams) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [ChannelQRSession]()
@@ -2350,6 +2524,7 @@ Client exposes Forward resources. Configure options before sharing a client.
```go
type Client struct {
+ Dreams DreamService
Webhooks WebhookService
Options []option.RequestOption
Templates TemplateService
@@ -3229,6 +3404,483 @@ func (r *DeletedSkillVersion) UnmarshalJSON(data []byte) error
+
+## type [Dream]()
+
+
+
+```go
+type Dream struct {
+ ID string `json:"id"`
+ Type string `json:"type"`
+ Status string `json:"status"`
+ Inputs []DreamInput `json:"inputs"`
+ Outputs []DreamOutput `json:"outputs"`
+ Model DreamModelConfig `json:"model"`
+ Instructions string `json:"instructions"`
+ Usage DreamUsage `json:"usage"`
+ Error DreamError `json:"error"`
+ CreatedAt time.Time `json:"created_at"`
+ EndedAt time.Time `json:"ended_at"`
+ ArchivedAt time.Time `json:"archived_at"`
+ JSON struct {
+ ID respjson.Field
+ Type respjson.Field
+ Status respjson.Field
+ Inputs respjson.Field
+ Outputs respjson.Field
+ Model respjson.Field
+ Instructions respjson.Field
+ Usage respjson.Field
+ Error respjson.Field
+ CreatedAt respjson.Field
+ EndedAt respjson.Field
+ ArchivedAt respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(Dream\) [RawJSON]()
+
+```go
+func (r Dream) RawJSON() string
+```
+
+
+
+
+### func \(\*Dream\) [UnmarshalJSON]()
+
+```go
+func (r *Dream) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamError]()
+
+
+
+```go
+type DreamError struct {
+ Type string `json:"type"`
+ Code string `json:"code"`
+ Message string `json:"message"`
+ JSON struct {
+ Type respjson.Field
+ Code respjson.Field
+ Message respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(DreamError\) [RawJSON]()
+
+```go
+func (r DreamError) RawJSON() string
+```
+
+
+
+
+### func \(\*DreamError\) [UnmarshalJSON]()
+
+```go
+func (r *DreamError) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamInput]()
+
+
+
+```go
+type DreamInput struct {
+ Type string `json:"type"`
+ MemoryStoreID string `json:"memory_store_id"`
+ IdentityID string `json:"identity_id"`
+ TemplateID string `json:"template_id"`
+ SessionIDs []string `json:"session_ids"`
+ JSON struct {
+ Type respjson.Field
+ MemoryStoreID respjson.Field
+ IdentityID respjson.Field
+ TemplateID respjson.Field
+ SessionIDs respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(DreamInput\) [RawJSON]()
+
+```go
+func (r DreamInput) RawJSON() string
+```
+
+
+
+
+### func \(\*DreamInput\) [UnmarshalJSON]()
+
+```go
+func (r *DreamInput) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamInputParam]()
+
+
+
+```go
+type DreamInputParam struct {
+ Type string `json:"type"`
+ MemoryStoreID param.Opt[string] `json:"memory_store_id,omitzero"`
+ IdentityID param.Opt[string] `json:"identity_id,omitzero"`
+ TemplateID param.Opt[string] `json:"template_id,omitzero"`
+ SessionIDs []string `json:"session_ids,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(DreamInputParam\) [MarshalJSON]()
+
+```go
+func (r DreamInputParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*DreamInputParam\) [UnmarshalJSON]()
+
+```go
+func (r *DreamInputParam) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamListParams]()
+
+
+
+```go
+type DreamListParams struct {
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
+ BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
+ IncludeArchived param.Opt[bool] `query:"include_archived,omitzero" json:"-"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(DreamListParams\) [URLQuery]()
+
+```go
+func (r DreamListParams) URLQuery() (url.Values, error)
+```
+
+
+
+
+## type [DreamModelConfig]()
+
+
+
+```go
+type DreamModelConfig struct {
+ ID string `json:"id"`
+ Effort string `json:"effort"`
+ ContextWindow int64 `json:"context_window"`
+ JSON struct {
+ ID respjson.Field
+ Effort respjson.Field
+ ContextWindow respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(DreamModelConfig\) [RawJSON]()
+
+```go
+func (r DreamModelConfig) RawJSON() string
+```
+
+
+
+
+### func \(\*DreamModelConfig\) [UnmarshalJSON]()
+
+```go
+func (r *DreamModelConfig) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamModelConfigParam]()
+
+
+
+```go
+type DreamModelConfigParam struct {
+ ID string `json:"id"`
+ Effort param.Opt[string] `json:"effort,omitzero"`
+ ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(DreamModelConfigParam\) [MarshalJSON]()
+
+```go
+func (r DreamModelConfigParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*DreamModelConfigParam\) [UnmarshalJSON]()
+
+```go
+func (r *DreamModelConfigParam) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamNewParams]()
+
+
+
+```go
+type DreamNewParams struct {
+ Inputs []DreamInputParam `json:"inputs,omitzero"`
+ Model DreamNewParamsModelUnion `json:"model,omitzero"`
+ Instructions param.Opt[string] `json:"instructions,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(DreamNewParams\) [MarshalJSON]()
+
+```go
+func (r DreamNewParams) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*DreamNewParams\) [UnmarshalJSON]()
+
+```go
+func (r *DreamNewParams) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamNewParamsModelUnion]()
+
+DreamNewParamsModelUnion accepts a model ID or tuning object; omit to use auto.
+
+```go
+type DreamNewParamsModelUnion struct {
+ OfString param.Opt[string] `json:",omitzero,inline"`
+ OfConfig *DreamModelConfigParam `json:",omitzero,inline"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(DreamNewParamsModelUnion\) [MarshalJSON]()
+
+```go
+func (r DreamNewParamsModelUnion) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*DreamNewParamsModelUnion\) [UnmarshalJSON]()
+
+```go
+func (r *DreamNewParamsModelUnion) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamOutput]()
+
+
+
+```go
+type DreamOutput struct {
+ Type string `json:"type"`
+ MemoryStoreID string `json:"memory_store_id"`
+ FilesTouched []string `json:"files_touched"`
+ JSON struct {
+ Type respjson.Field
+ MemoryStoreID respjson.Field
+ FilesTouched respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(DreamOutput\) [RawJSON]()
+
+```go
+func (r DreamOutput) RawJSON() string
+```
+
+
+
+
+### func \(\*DreamOutput\) [UnmarshalJSON]()
+
+```go
+func (r *DreamOutput) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [DreamService]()
+
+DreamService consolidates Forward memory; requires PAT or an admin SAT.
+
+```go
+type DreamService struct{ Options []option.RequestOption }
+```
+
+
+### func [NewDreamService]()
+
+```go
+func NewDreamService(opts ...option.RequestOption) DreamService
+```
+
+
+
+
+### func \(\*DreamService\) [Archive]()
+
+```go
+func (r *DreamService) Archive(ctx context.Context, dreamID string, opts ...option.RequestOption) (res *Dream, err error)
+```
+
+
+
+
+### func \(\*DreamService\) [Cancel]()
+
+```go
+func (r *DreamService) Cancel(ctx context.Context, dreamID string, opts ...option.RequestOption) (res *Dream, err error)
+```
+
+
+
+
+### func \(\*DreamService\) [Get]()
+
+```go
+func (r *DreamService) Get(ctx context.Context, dreamID string, opts ...option.RequestOption) (res *Dream, err error)
+```
+
+
+
+
+### func \(\*DreamService\) [List]()
+
+```go
+func (r *DreamService) List(ctx context.Context, params DreamListParams, opts ...option.RequestOption) (res *pagination.Page[Dream], err error)
+```
+
+
+
+
+### func \(\*DreamService\) [ListAutoPaging]()
+
+```go
+func (r *DreamService) ListAutoPaging(ctx context.Context, params DreamListParams, opts ...option.RequestOption) *pagination.PageAutoPager[Dream]
+```
+
+
+
+
+### func \(\*DreamService\) [New]()
+
+```go
+func (r *DreamService) New(ctx context.Context, params DreamNewParams, opts ...option.RequestOption) (res *Dream, err error)
+```
+
+
+
+
+## type [DreamUsage]()
+
+
+
+```go
+type DreamUsage struct {
+ InputTokens int64 `json:"input_tokens"`
+ OutputTokens int64 `json:"output_tokens"`
+ CacheCreationInputTokens int64 `json:"cache_creation_input_tokens"`
+ CacheReadInputTokens int64 `json:"cache_read_input_tokens"`
+ JSON struct {
+ InputTokens respjson.Field
+ OutputTokens respjson.Field
+ CacheCreationInputTokens respjson.Field
+ CacheReadInputTokens respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(DreamUsage\) [RawJSON]()
+
+```go
+func (r DreamUsage) RawJSON() string
+```
+
+
+
+
+### func \(\*DreamUsage\) [UnmarshalJSON]()
+
+```go
+func (r *DreamUsage) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [DriveClearParams]()
@@ -4968,6 +5620,7 @@ func (r *GitHubRepositoryParam) UnmarshalJSON(data []byte) error
```go
type Identity struct {
+ AutoMemoryStore bool `json:"auto_memory_store"`
// Forward Identity ID; the `idn_` prefix is recommended.
ID string `json:"id"`
// End-user ID in the integrator's system.
@@ -4985,15 +5638,16 @@ type Identity struct {
// Last update time, in RFC 3339 format.
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
JSON struct {
- ID respjson.Field
- ExternalID respjson.Field
- Name respjson.Field
- IdentityType respjson.Field
- Enabled respjson.Field
- Metadata respjson.Field
- CreatedAt respjson.Field
- UpdatedAt respjson.Field
- ExtraFields map[string]respjson.Field
+ AutoMemoryStore respjson.Field
+ ID respjson.Field
+ ExternalID respjson.Field
+ Name respjson.Field
+ IdentityType respjson.Field
+ Enabled respjson.Field
+ Metadata respjson.Field
+ CreatedAt respjson.Field
+ UpdatedAt respjson.Field
+ ExtraFields map[string]respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -5296,9 +5950,10 @@ Create or update Identity Config
```go
type IdentityConfigSpec struct {
+ ManagedToolConfig map[string]*ManagedCapabilityOverride `json:"managed_tool_config"`
System SystemOverride `json:"system"`
Model ModelConfig `json:"model"`
- Tools map[string]ToolOverride `json:"tools"`
+ Tools IdentityToolsUnion `json:"tools"`
MCPServers map[string]MCPServerOverride `json:"mcp_servers"`
Skills map[string]SkillOverride `json:"skills"`
Toolsets map[string]any `json:"toolsets"`
@@ -5308,6 +5963,7 @@ type IdentityConfigSpec struct {
GitHubRepositories map[string]GitHubRepository `json:"github_repositories"`
EnvironmentVariables map[string]EnvironmentVariableOverride `json:"environment_variables"`
JSON struct {
+ ManagedToolConfig respjson.Field
System respjson.Field
Model respjson.Field
Tools respjson.Field
@@ -5350,9 +6006,10 @@ func (r *IdentityConfigSpec) UnmarshalJSON(data []byte) error
```go
type IdentityConfigSpecParam struct {
+ ManagedToolConfig map[string]ManagedCapabilityOverrideParam `json:"managed_tool_config,omitzero"`
System SystemOverrideParam `json:"system,omitzero"`
Model ModelConfigUnionParam `json:"model,omitzero"`
- Tools map[string]ToolOverrideParam `json:"tools,omitzero"`
+ Tools IdentityToolsUnionParam `json:"tools,omitzero"`
MCPServers map[string]MCPServerOverrideParam `json:"mcp_servers,omitzero"`
Skills map[string]SkillOverrideParam `json:"skills,omitzero"`
Toolsets map[string]any `json:"toolsets,omitzero"`
@@ -5489,6 +6146,29 @@ func (r *IdentityListTemplatesResponse) UnmarshalJSON(data []byte) error
+
+## type [IdentityMemoryStoreListParams]()
+
+
+
+```go
+type IdentityMemoryStoreListParams struct {
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
+ BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(IdentityMemoryStoreListParams\) [URLQuery]()
+
+```go
+func (r IdentityMemoryStoreListParams) URLQuery() (url.Values, error)
+```
+
+
+
## type [IdentityMemoryStoreListResponse]()
@@ -5496,9 +6176,13 @@ func (r *IdentityListTemplatesResponse) UnmarshalJSON(data []byte) error
```go
type IdentityMemoryStoreListResponse struct {
+ FirstID string `json:"first_id"`
+ LastID string `json:"last_id"`
Data []MemoryStoreMount `json:"data"`
HasMore bool `json:"has_more"`
JSON struct {
+ FirstID respjson.Field
+ LastID respjson.Field
Data respjson.Field
HasMore respjson.Field
ExtraFields map[string]respjson.Field
@@ -5532,6 +6216,7 @@ func (r *IdentityMemoryStoreListResponse) UnmarshalJSON(data []byte) error
```go
type IdentityMemoryStoreMountParams struct {
+ Access param.Opt[string] `json:"access,omitzero"`
// ID of the Memory Store to mount (`memstore_...`). It must be an active Store
// visible to the caller.
MemoryStoreID string `json:"memory_store_id" api:"required"`
@@ -5590,11 +6275,20 @@ Unmount Memory Store from an Identity
### func \(\*IdentityMemoryStoreService\) [List]()
```go
-func (r *IdentityMemoryStoreService) List(ctx context.Context, identityID string, templateID string, opts ...option.RequestOption) (res *IdentityMemoryStoreListResponse, err error)
+func (r *IdentityMemoryStoreService) List(ctx context.Context, identityID string, templateID string, params IdentityMemoryStoreListParams, opts ...option.RequestOption) (res *pagination.Page[MemoryStoreMount], err error)
```
List Memory Store mounts on an Identity
+
+### func \(\*IdentityMemoryStoreService\) [ListAutoPaging]()
+
+```go
+func (r *IdentityMemoryStoreService) ListAutoPaging(ctx context.Context, identityID, templateID string, params IdentityMemoryStoreListParams, opts ...option.RequestOption) *pagination.PageAutoPager[MemoryStoreMount]
+```
+
+
+
### func \(\*IdentityMemoryStoreService\) [Mount]()
@@ -5611,6 +6305,7 @@ Mount Memory Store on an Identity
```go
type IdentityNewParams struct {
+ AutoMemoryStore param.Opt[bool] `json:"auto_memory_store,omitzero"`
// End-user ID in the integrator's system; cannot be empty or whitespace only.
ExternalID string `json:"external_id" api:"required"`
// Display name; when provided it cannot be empty or whitespace only.
@@ -5887,6 +6582,68 @@ func (r *IdentityTemplate) UnmarshalJSON(data []byte) error
+
+## type [IdentityToolsUnion]()
+
+
+
+```go
+type IdentityToolsUnion struct {
+ OfOverrides map[string]*ToolOverride
+ OfArray []Tool
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(IdentityToolsUnion\) [RawJSON]()
+
+```go
+func (r IdentityToolsUnion) RawJSON() string
+```
+
+
+
+
+### func \(\*IdentityToolsUnion\) [UnmarshalJSON]()
+
+```go
+func (r *IdentityToolsUnion) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [IdentityToolsUnionParam]()
+
+IdentityToolsUnionParam overrides individual tools or replaces the complete tools array.
+
+```go
+type IdentityToolsUnionParam struct {
+ OfOverrides map[string]ToolOverrideParam `json:",omitzero,inline"`
+ OfArray []ToolParam `json:",omitzero,inline"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(IdentityToolsUnionParam\) [MarshalJSON]()
+
+```go
+func (r IdentityToolsUnionParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*IdentityToolsUnionParam\) [UnmarshalJSON]()
+
+```go
+func (r *IdentityToolsUnionParam) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [IdentityUpdateParams]()
@@ -5894,6 +6651,7 @@ func (r *IdentityTemplate) UnmarshalJSON(data []byte) error
```go
type IdentityUpdateParams struct {
+ AutoMemoryStore param.Opt[bool] `json:"auto_memory_store,omitzero"`
// Replaces the existing end-user ID.
ExternalID param.Opt[string] `json:"external_id,omitzero"`
// Replaces the display name.
@@ -6250,6 +7008,70 @@ func (r *MCPServerParam) UnmarshalJSON(data []byte) error
+
+## type [ManagedCapabilityOverride]()
+
+
+
+```go
+type ManagedCapabilityOverride struct {
+ Enabled bool `json:"enabled"`
+ JSON struct {
+ Enabled respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(ManagedCapabilityOverride\) [RawJSON]()
+
+```go
+func (r ManagedCapabilityOverride) RawJSON() string
+```
+
+
+
+
+### func \(\*ManagedCapabilityOverride\) [UnmarshalJSON]()
+
+```go
+func (r *ManagedCapabilityOverride) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [ManagedCapabilityOverrideParam]()
+
+ManagedCapabilityOverrideParam is a sparse Identity capability switch. Use param.NullStruct to restore inheritance for one selector.
+
+```go
+type ManagedCapabilityOverrideParam struct {
+ Enabled bool `json:"enabled" api:"required"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(ManagedCapabilityOverrideParam\) [MarshalJSON]()
+
+```go
+func (r ManagedCapabilityOverrideParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*ManagedCapabilityOverrideParam\) [UnmarshalJSON]()
+
+```go
+func (r *ManagedCapabilityOverrideParam) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [ManagedToolConfig]()
@@ -7320,10 +8142,13 @@ func (r *MultiagentConfigParam) UnmarshalJSON(data []byte) error
```go
type MultiagentEntry struct {
+ OfString string `json:"-"`
+ Model string `json:"model"`
Type string `json:"type" api:"required"`
TemplateID string `json:"template_id"`
Name string `json:"name"`
JSON struct {
+ Model respjson.Field
Type respjson.Field
TemplateID respjson.Field
Name respjson.Field
@@ -7342,6 +8167,15 @@ func (r MultiagentEntry) RawJSON() string
+
+### func \(\*MultiagentEntry\) [UnmarshalAPIJSON]()
+
+```go
+func (r *MultiagentEntry) UnmarshalAPIJSON(data []byte) error
+```
+
+UnmarshalAPIJSON keeps string roster entries intact when nested in a Template.
+
### func \(\*MultiagentEntry\) [UnmarshalJSON]()
@@ -7358,6 +8192,8 @@ func (r *MultiagentEntry) UnmarshalJSON(data []byte) error
```go
type MultiagentEntryParam struct {
+ OfString param.Opt[string] `json:"-"`
+ Model param.Opt[string] `json:"model,omitzero"`
Type string `json:"type" api:"required"`
TemplateID param.Opt[string] `json:"template_id,omitzero"`
Name param.Opt[string] `json:"name,omitzero"`
@@ -7374,6 +8210,15 @@ func (r MultiagentEntryParam) MarshalJSON() ([]byte, error)
+
+### func \(\*MultiagentEntryParam\) [UnmarshalAPIJSON]()
+
+```go
+func (r *MultiagentEntryParam) UnmarshalAPIJSON(data []byte) error
+```
+
+
+
### func \(\*MultiagentEntryParam\) [UnmarshalJSON]()
@@ -7383,6 +8228,76 @@ func (r *MultiagentEntryParam) UnmarshalJSON(data []byte) error
+
+## type [OutcomeRubric]()
+
+OutcomeRubric contains the text or file reference used to evaluate an Outcome.
+
+```go
+type OutcomeRubric struct {
+ Type string `json:"type"`
+ Content string `json:"content"`
+ FileID string `json:"file_id"`
+ JSON struct {
+ Type respjson.Field
+ Content respjson.Field
+ FileID respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(OutcomeRubric\) [RawJSON]()
+
+```go
+func (r OutcomeRubric) RawJSON() string
+```
+
+
+
+
+### func \(\*OutcomeRubric\) [UnmarshalJSON]()
+
+```go
+func (r *OutcomeRubric) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [OutcomeRubricParam]()
+
+OutcomeRubricParam defines acceptance criteria as inline text or an uploaded file. Set Type to "text" with Content, or "file" with FileID.
+
+```go
+type OutcomeRubricParam struct {
+ Type string `json:"type" api:"required"`
+ Content param.Opt[string] `json:"content,omitzero"`
+ FileID param.Opt[string] `json:"file_id,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(OutcomeRubricParam\) [MarshalJSON]()
+
+```go
+func (r OutcomeRubricParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*OutcomeRubricParam\) [UnmarshalJSON]()
+
+```go
+func (r *OutcomeRubricParam) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [PermissionPolicy]()
@@ -8436,6 +9351,7 @@ func (s *ResumableSessionEventStream) Next() bool
```go
type Schedule struct {
+ Resources []ScheduleFileResource `json:"resources"`
// Authoritative creation method of the Schedule: api or tool.
Source string `json:"source"`
SourceSessionID string `json:"source_session_id" api:"nullable"`
@@ -8458,6 +9374,7 @@ type Schedule struct {
ArchivedAt time.Time `json:"archived_at" format:"date-time"`
PausedReason SchedulePausedReason `json:"paused_reason"`
JSON struct {
+ Resources respjson.Field
Source respjson.Field
SourceSessionID respjson.Field
InitialEventsVersion respjson.Field
@@ -8635,6 +9552,76 @@ func (r *ScheduleExecution) UnmarshalJSON(data []byte) error
+
+## type [ScheduleFileResource]()
+
+
+
+```go
+type ScheduleFileResource struct {
+ Type string `json:"type"`
+ FileID string `json:"file_id"`
+ MountPath string `json:"mount_path"`
+ JSON struct {
+ Type respjson.Field
+ FileID respjson.Field
+ MountPath respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(ScheduleFileResource\) [RawJSON]()
+
+```go
+func (r ScheduleFileResource) RawJSON() string
+```
+
+
+
+
+### func \(\*ScheduleFileResource\) [UnmarshalJSON]()
+
+```go
+func (r *ScheduleFileResource) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [ScheduleFileResourceParam]()
+
+ScheduleFileResourceParam attaches a Forward file to each Schedule run.
+
+```go
+type ScheduleFileResourceParam struct {
+ Type string `json:"type" api:"required"`
+ FileID string `json:"file_id" api:"required"`
+ MountPath param.Opt[string] `json:"mount_path,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(ScheduleFileResourceParam\) [MarshalJSON]()
+
+```go
+func (r ScheduleFileResourceParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*ScheduleFileResourceParam\) [UnmarshalJSON]()
+
+```go
+func (r *ScheduleFileResourceParam) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [ScheduleInitialEventsItem]()
@@ -8718,6 +9705,7 @@ func (r ScheduleListParams) URLQuery() (url.Values, error)
```go
type ScheduleNewParams struct {
+ Resources []ScheduleFileResourceParam `json:"resources,omitzero"`
// Forward Identity ID the Schedule belongs to.
IdentityID string `json:"identity_id" api:"required"`
// Forward Template ID to execute.
@@ -8826,6 +9814,7 @@ func (r *SchedulePausedReason) UnmarshalJSON(data []byte) error
```go
type ScheduleRun struct {
+ InitialEvents []SessionEvent `json:"initial_events"`
// Authoritative creation method of the Schedule: api or tool.
Source string `json:"source"`
SourceSessionID string `json:"source_session_id" api:"nullable"`
@@ -8872,6 +9861,7 @@ type ScheduleRun struct {
// null|Human-readable error message; structured details stay in `error`.
ErrorMessage string `json:"error_message"`
JSON struct {
+ InitialEvents respjson.Field
Source respjson.Field
SourceSessionID respjson.Field
InitialEventsVersion respjson.Field
@@ -8925,6 +9915,7 @@ func (r *ScheduleRun) UnmarshalJSON(data []byte) error
```go
type ScheduleRunGetParams struct {
+ IncludeInitialEvents param.Opt[bool] `query:"include_initial_events,omitzero" json:"-"`
// Additional ownership constraint.
IdentityID param.Opt[string] `query:"identity_id,omitzero" json:"-"`
// contains filtered or unexported fields
@@ -9344,6 +10335,7 @@ func (r ScheduleUnpauseParams) URLQuery() (url.Values, error)
```go
type ScheduleUpdateParams struct {
+ Resources []ScheduleFileResourceParam `json:"resources,omitzero"`
// New Schedule name.
Name param.Opt[string] `json:"name,omitzero"`
// New Schedule description.
@@ -9807,7 +10799,7 @@ type SessionEvent struct {
Result string `json:"result"`
DenyMessage string `json:"deny_message"`
Description string `json:"description"`
- Rubric string `json:"rubric"`
+ Rubric OutcomeRubric `json:"rubric"`
OutcomeID string `json:"outcome_id"`
MaxIterations int64 `json:"max_iterations"`
MessageID string `json:"message_id"`
@@ -9956,7 +10948,7 @@ type SessionEventParam struct {
DenyMessage param.Opt[string] `json:"deny_message,omitzero"`
IsError param.Opt[bool] `json:"is_error,omitzero"`
Description param.Opt[string] `json:"description,omitzero"`
- Rubric param.Opt[string] `json:"rubric,omitzero"`
+ Rubric OutcomeRubricParam `json:"rubric,omitzero"`
OutcomeID param.Opt[string] `json:"outcome_id,omitzero"`
MaxIterations param.Opt[int64] `json:"max_iterations,omitzero"`
// contains filtered or unexported fields
@@ -10573,7 +11565,7 @@ func (r *SessionService) ListAutoPaging(ctx context.Context, params SessionListP
func (r *SessionService) New(ctx context.Context, params SessionNewParams, opts ...option.RequestOption) (res *Session, err error)
```
-Create Session
+Create Session. Adds \_\_qca\_sdk\_ metadata; conflicting reserved values fail before sending.
### func \(\*SessionService\) [Update]()
@@ -13847,6 +14839,12 @@ Qoder managed API definitions.
- [type BrowserStateTabEntryParam](<#BrowserStateTabEntryParam>)
- [func \(r BrowserStateTabEntryParam\) MarshalJSON\(\) \(data \[\]byte, err error\)](<#BrowserStateTabEntryParam.MarshalJSON>)
- [func \(r \*BrowserStateTabEntryParam\) UnmarshalJSON\(data \[\]byte\) error](<#BrowserStateTabEntryParam.UnmarshalJSON>)
+- [type BucketStorage](<#BucketStorage>)
+ - [func \(r BucketStorage\) RawJSON\(\) string](<#BucketStorage.RawJSON>)
+ - [func \(r \*BucketStorage\) UnmarshalJSON\(data \[\]byte\) error](<#BucketStorage.UnmarshalJSON>)
+- [type BucketStorageParam](<#BucketStorageParam>)
+ - [func \(r BucketStorageParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#BucketStorageParam.MarshalJSON>)
+ - [func \(r \*BucketStorageParam\) UnmarshalJSON\(data \[\]byte\) error](<#BucketStorageParam.UnmarshalJSON>)
- [type CacheControlEphemeralParam](<#CacheControlEphemeralParam>)
- [func \(r CacheControlEphemeralParam\) MarshalJSON\(\) \(data \[\]byte, err error\)](<#CacheControlEphemeralParam.MarshalJSON>)
- [func \(r \*CacheControlEphemeralParam\) UnmarshalJSON\(data \[\]byte\) error](<#CacheControlEphemeralParam.UnmarshalJSON>)
@@ -14091,10 +15089,8 @@ Qoder managed API definitions.
- [func \(r DreamModelConfig\) RawJSON\(\) string](<#DreamModelConfig.RawJSON>)
- [func \(r \*DreamModelConfig\) UnmarshalJSON\(data \[\]byte\) error](<#DreamModelConfig.UnmarshalJSON>)
- [type DreamModelConfigParam](<#DreamModelConfigParam>)
- - [func \(r DreamModelConfigParam\) MarshalJSON\(\) \(data \[\]byte, err error\)](<#DreamModelConfigParam.MarshalJSON>)
+ - [func \(r DreamModelConfigParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#DreamModelConfigParam.MarshalJSON>)
- [func \(r \*DreamModelConfigParam\) UnmarshalJSON\(data \[\]byte\) error](<#DreamModelConfigParam.UnmarshalJSON>)
-- [type DreamModelConfigParamSpeed](<#DreamModelConfigParamSpeed>)
-- [type DreamModelConfigSpeed](<#DreamModelConfigSpeed>)
- [type DreamNewParams](<#DreamNewParams>)
- [func \(r DreamNewParams\) MarshalJSON\(\) \(data \[\]byte, err error\)](<#DreamNewParams.MarshalJSON>)
- [func \(r \*DreamNewParams\) UnmarshalJSON\(data \[\]byte\) error](<#DreamNewParams.UnmarshalJSON>)
@@ -16345,6 +17341,27 @@ Qoder managed API definitions.
- [type MonetaryAmountParam](<#MonetaryAmountParam>)
- [func \(r MonetaryAmountParam\) MarshalJSON\(\) \(data \[\]byte, err error\)](<#MonetaryAmountParam.MarshalJSON>)
- [func \(r \*MonetaryAmountParam\) UnmarshalJSON\(data \[\]byte\) error](<#MonetaryAmountParam.UnmarshalJSON>)
+- [type OAuthService](<#OAuthService>)
+ - [func NewOAuthService\(opts ...option.RequestOption\) OAuthService](<#NewOAuthService>)
+ - [func \(r \*OAuthService\) Start\(ctx context.Context, params OAuthStartParams, opts ...option.RequestOption\) \(res \*OAuthStartResponse, err error\)](<#OAuthService.Start>)
+- [type OAuthStartParams](<#OAuthStartParams>)
+ - [func \(r OAuthStartParams\) MarshalJSON\(\) \(\[\]byte, error\)](<#OAuthStartParams.MarshalJSON>)
+ - [func \(r \*OAuthStartParams\) UnmarshalJSON\(data \[\]byte\) error](<#OAuthStartParams.UnmarshalJSON>)
+- [type OAuthStartResponse](<#OAuthStartResponse>)
+ - [func \(r OAuthStartResponse\) RawJSON\(\) string](<#OAuthStartResponse.RawJSON>)
+ - [func \(r \*OAuthStartResponse\) UnmarshalJSON\(data \[\]byte\) error](<#OAuthStartResponse.UnmarshalJSON>)
+- [type OSSBucket](<#OSSBucket>)
+ - [func \(r OSSBucket\) RawJSON\(\) string](<#OSSBucket.RawJSON>)
+ - [func \(r \*OSSBucket\) UnmarshalJSON\(data \[\]byte\) error](<#OSSBucket.UnmarshalJSON>)
+- [type OSSBucketCredential](<#OSSBucketCredential>)
+ - [func \(r OSSBucketCredential\) RawJSON\(\) string](<#OSSBucketCredential.RawJSON>)
+ - [func \(r \*OSSBucketCredential\) UnmarshalJSON\(data \[\]byte\) error](<#OSSBucketCredential.UnmarshalJSON>)
+- [type OSSBucketCredentialParam](<#OSSBucketCredentialParam>)
+ - [func \(r OSSBucketCredentialParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#OSSBucketCredentialParam.MarshalJSON>)
+ - [func \(r \*OSSBucketCredentialParam\) UnmarshalJSON\(data \[\]byte\) error](<#OSSBucketCredentialParam.UnmarshalJSON>)
+- [type OSSBucketParam](<#OSSBucketParam>)
+ - [func \(r OSSBucketParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#OSSBucketParam.MarshalJSON>)
+ - [func \(r \*OSSBucketParam\) UnmarshalJSON\(data \[\]byte\) error](<#OSSBucketParam.UnmarshalJSON>)
- [type OutputBehaviorCreateNew](<#OutputBehaviorCreateNew>)
- [func \(r OutputBehaviorCreateNew\) RawJSON\(\) string](<#OutputBehaviorCreateNew.RawJSON>)
- [func \(r OutputBehaviorCreateNew\) ToParam\(\) OutputBehaviorCreateNewParam](<#OutputBehaviorCreateNew.ToParam>)
@@ -18426,6 +19443,70 @@ func (r *BrowserStateTabEntryParam) UnmarshalJSON(data []byte) error
+
+## type [BucketStorage]()
+
+
+
+```go
+type BucketStorage struct {
+ Buckets []OSSBucket `json:"buckets"`
+ JSON struct {
+ Buckets respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(BucketStorage\) [RawJSON]()
+
+```go
+func (r BucketStorage) RawJSON() string
+```
+
+
+
+
+### func \(\*BucketStorage\) [UnmarshalJSON]()
+
+```go
+func (r *BucketStorage) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [BucketStorageParam]()
+
+BucketStorageParam declares up to eight OSS bucket mounts in a cloud Environment.
+
+```go
+type BucketStorageParam struct {
+ Buckets []OSSBucketParam `json:"buckets" api:"required"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(BucketStorageParam\) [MarshalJSON]()
+
+```go
+func (r BucketStorageParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*BucketStorageParam\) [UnmarshalJSON]()
+
+```go
+func (r *BucketStorageParam) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [CacheControlEphemeralParam]()
@@ -18768,6 +19849,7 @@ Client exposes concrete services; nested services follow the upstream hierarchy.
```go
type Client struct {
+ OAuth OAuthService
Options []option.RequestOption
Agents AgentService
Sessions SessionService
@@ -18799,7 +19881,9 @@ NewClient uses common authentication defaults and QODER\_BASE\_URL. Explicit opt
```go
type CloudConfig struct {
- SetupScript string `json:"setup_script"`
+ // Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
+ Storage BucketStorage `json:"storage"`
+ SetupScript string `json:"setup_script"`
// Network configuration policy.
Networking CloudConfigNetworkingUnion `json:"networking" api:"required"`
// Package manager configuration.
@@ -18808,6 +19892,7 @@ type CloudConfig struct {
Type constant.Cloud `json:"type" default:"cloud"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
+ Storage respjson.Field
SetupScript respjson.Field
Networking respjson.Field
Packages respjson.Field
@@ -18930,7 +20015,9 @@ The property Type is required.
```go
type CloudConfigParams struct {
- SetupScript param.Opt[string] `json:"setup_script,omitzero"`
+ // Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
+ Storage BucketStorageParam `json:"storage,omitzero"`
+ SetupScript param.Opt[string] `json:"setup_script,omitzero"`
// Network configuration policy. Omit on update to preserve the existing value.
Networking CloudConfigParamsNetworkingUnion `json:"networking,omitzero"`
// Specify packages (and optionally their versions) available in this environment.
@@ -21363,19 +22450,14 @@ Model identifier and configuration applied to every pipeline stage. Same wire sh
```go
type DreamModelConfig struct {
- // Model identifier. 1-256 characters.
- ID string `json:"id" api:"required"`
- // Inference speed mode. `fast` provides significantly faster output token
- // generation at premium pricing. Not all models support `fast`; invalid
- // combinations are rejected at create time.
- //
- // Any of "standard", "fast".
- Speed DreamModelConfigSpeed `json:"speed"`
- // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
- JSON struct {
- ID respjson.Field
- Speed respjson.Field
- ExtraFields map[string]respjson.Field
+ ID string `json:"id"`
+ Effort string `json:"effort"`
+ ContextWindow int64 `json:"context_window"`
+ JSON struct {
+ ID respjson.Field
+ Effort respjson.Field
+ ContextWindow respjson.Field
+ ExtraFields map[string]respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -21388,7 +22470,7 @@ type DreamModelConfig struct {
func (r DreamModelConfig) RawJSON() string
```
-Returns the unmodified JSON received from the API
+
### func \(\*DreamModelConfig\) [UnmarshalJSON]()
@@ -21402,20 +22484,13 @@ func (r *DreamModelConfig) UnmarshalJSON(data []byte) error
## type [DreamModelConfigParam]()
-Model identifier and configuration applied to every pipeline stage.
-
-The property ID is required.
+DreamModelConfigParam selects an available model and optional reasoning settings.
```go
type DreamModelConfigParam struct {
- // Model identifier. 1-256 characters.
- ID string `json:"id" api:"required"`
- // Inference speed mode. `fast` provides significantly faster output token
- // generation at premium pricing. Not all models support `fast`; invalid
- // combinations are rejected at create time.
- //
- // Any of "standard", "fast".
- Speed DreamModelConfigParamSpeed `json:"speed,omitzero"`
+ ID string `json:"id" api:"required"`
+ Effort param.Opt[string] `json:"effort,omitzero"`
+ ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
// contains filtered or unexported fields
}
```
@@ -21424,7 +22499,7 @@ type DreamModelConfigParam struct {
### func \(DreamModelConfigParam\) [MarshalJSON]()
```go
-func (r DreamModelConfigParam) MarshalJSON() (data []byte, err error)
+func (r DreamModelConfigParam) MarshalJSON() ([]byte, error)
```
@@ -21438,42 +22513,6 @@ func (r *DreamModelConfigParam) UnmarshalJSON(data []byte) error
-
-## type [DreamModelConfigParamSpeed]()
-
-Inference speed mode. \`fast\` provides significantly faster output token generation at premium pricing. Not all models support \`fast\`; invalid combinations are rejected at create time.
-
-```go
-type DreamModelConfigParamSpeed string
-```
-
-
-
-```go
-const (
- DreamModelConfigParamSpeedStandard DreamModelConfigParamSpeed = "standard"
- DreamModelConfigParamSpeedFast DreamModelConfigParamSpeed = "fast"
-)
-```
-
-
-## type [DreamModelConfigSpeed]()
-
-Inference speed mode. \`fast\` provides significantly faster output token generation at premium pricing. Not all models support \`fast\`; invalid combinations are rejected at create time.
-
-```go
-type DreamModelConfigSpeed string
-```
-
-
-
-```go
-const (
- DreamModelConfigSpeedStandard DreamModelConfigSpeed = "standard"
- DreamModelConfigSpeedFast DreamModelConfigSpeed = "fast"
-)
-```
-
## type [DreamNewParams]()
@@ -21483,7 +22522,7 @@ const (
type DreamNewParams struct {
Inputs []DreamInputUnionParam `json:"inputs,omitzero" api:"required"`
// Model identifier and configuration applied to every pipeline stage.
- Model DreamNewParamsModelUnion `json:"model,omitzero" api:"required"`
+ Model DreamNewParamsModelUnion `json:"model,omitzero"`
Instructions param.Opt[string] `json:"instructions,omitzero"`
// The default destination: the job creates a new output memory store as a clone of
// the memory_store input and writes the consolidated memories into it. The input
@@ -22042,7 +23081,9 @@ Use the methods beginning with 'As' to cast the union to one of its variants.
```go
type EnvironmentConfigUnion struct {
- SetupScript string `json:"setup_script"`
+ // Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
+ Storage BucketStorage `json:"storage"`
+ SetupScript string `json:"setup_script"`
// This field is from variant [CloudConfig].
Networking CloudConfigNetworkingUnion `json:"networking"`
// This field is from variant [CloudConfig].
@@ -22050,6 +23091,7 @@ type EnvironmentConfigUnion struct {
// Any of "cloud", "self_hosted".
Type string `json:"type"`
JSON struct {
+ Storage respjson.Field
SetupScript respjson.Field
Networking respjson.Field
Packages respjson.Field
@@ -37367,34 +38409,18 @@ Model identifier and configuration.
```go
type ManagedAgentsModelConfig struct {
- ContextWindow int64 `json:"context_window"`
-
- // The model that will power your agent.
- //
- // See [models](https://docs.qoder.com/cloud-agents/api/models/list) for additional
- // details and options.
- ID ManagedAgentsModel `json:"id" api:"required"`
- // How hard the model works on each turn. Sets `output_config.effort` on every
- // Messages call the session makes.
- Effort ManagedAgentsModelConfigEffortUnion `json:"effort"`
- // Geographic region for model inference. When unset, requests fall through to the
- // workspace's default_inference_geo.
- InferenceGeo string `json:"inference_geo"`
- // Inference speed mode. `fast` provides significantly faster output token
- // generation at premium pricing. Not all models support `fast`; invalid
- // combinations are rejected at create time.
- //
- // Any of "standard", "fast".
- Speed ManagedAgentsModelConfigSpeed `json:"speed"`
- // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
- JSON struct {
- ContextWindow respjson.Field
-
- ID respjson.Field
- Effort respjson.Field
- InferenceGeo respjson.Field
- Speed respjson.Field
- ExtraFields map[string]respjson.Field
+ InferenceGeo string `json:"inference_geo"`
+ ID string `json:"id" api:"required"`
+ Effort string `json:"effort"`
+ ContextWindow int64 `json:"context_window"`
+ EffectiveContextWindow int64 `json:"effective_context_window"`
+ JSON struct {
+ InferenceGeo respjson.Field
+ ID respjson.Field
+ Effort respjson.Field
+ ContextWindow respjson.Field
+ EffectiveContextWindow respjson.Field
+ ExtraFields map[string]respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -37531,27 +38557,10 @@ The property ID is required.
```go
type ManagedAgentsModelConfigParams struct {
- ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
-
- // The model that will power your agent.
- //
- // See [models](https://docs.qoder.com/cloud-agents/api/models/list) for additional
- // details and options.
- ID ManagedAgentsModel `json:"id,omitzero" api:"required"`
- // Geographic region for model inference. When unset, requests fall through to the
- // workspace's default_inference_geo. On update, `model` is whole-object
- // replacement — omitting inference_geo clears it.
- InferenceGeo param.Opt[string] `json:"inference_geo,omitzero"`
- // How hard the model works on each inference call. Accepts a bare level string
- // (`"high"`) or `{"type": "high"}`. On create, omitting it resolves the per-model
- // default; on update, omitting it leaves the stored value unchanged.
- Effort ManagedAgentsModelConfigParamsEffortUnion `json:"effort,omitzero"`
- // Inference speed mode. `fast` provides significantly faster output token
- // generation at premium pricing. Not all models support `fast`; invalid
- // combinations are rejected at create time.
- //
- // Any of "standard", "fast".
- Speed ManagedAgentsModelConfigParamsSpeed `json:"speed,omitzero"`
+ InferenceGeo param.Opt[string] `json:"inference_geo,omitzero"`
+ ID string `json:"id" api:"required"`
+ Effort param.Opt[string] `json:"effort,omitzero"`
+ ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
// contains filtered or unexported fields
}
```
@@ -51601,7 +52610,9 @@ type MemoryStoreGetParams struct {
```go
type MemoryStoreListParams struct {
- Name param.Opt[string] `query:"name,omitzero" json:"-"`
+ AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
+ BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
+ Name param.Opt[string] `query:"name,omitzero" json:"-"`
// Return only stores whose `created_at` is at or after this time (inclusive). Sent
// on the wire as `created_at[gte]`.
@@ -52629,6 +53640,260 @@ func (r *MonetaryAmountParam) UnmarshalJSON(data []byte) error
+
+## type [OAuthService]()
+
+
+
+```go
+type OAuthService struct{ Options []option.RequestOption }
+```
+
+
+### func [NewOAuthService]()
+
+```go
+func NewOAuthService(opts ...option.RequestOption) OAuthService
+```
+
+
+
+
+### func \(\*OAuthService\) [Start]()
+
+```go
+func (r *OAuthService) Start(ctx context.Context, params OAuthStartParams, opts ...option.RequestOption) (res *OAuthStartResponse, err error)
+```
+
+Start returns an authorization URL; the user completes authorization in their browser.
+
+
+## type [OAuthStartParams]()
+
+
+
+```go
+type OAuthStartParams struct {
+ WorkspaceID param.Opt[string] `header:"qoder-workspace-id,omitzero" json:"-"`
+
+ VaultID string `json:"vault_id"`
+ MCPServerURL string `json:"mcp_server_url"`
+ ClientID param.Opt[string] `json:"client_id,omitzero"`
+ ClientSecret param.Opt[string] `json:"client_secret,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(OAuthStartParams\) [MarshalJSON]()
+
+```go
+func (r OAuthStartParams) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*OAuthStartParams\) [UnmarshalJSON]()
+
+```go
+func (r *OAuthStartParams) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [OAuthStartResponse]()
+
+
+
+```go
+type OAuthStartResponse struct {
+ AuthorizationURL string `json:"authorization_url"`
+ State string `json:"state"`
+ CallbackOrigin string `json:"callback_origin"`
+ JSON struct {
+ AuthorizationURL respjson.Field
+ State respjson.Field
+ CallbackOrigin respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(OAuthStartResponse\) [RawJSON]()
+
+```go
+func (r OAuthStartResponse) RawJSON() string
+```
+
+
+
+
+### func \(\*OAuthStartResponse\) [UnmarshalJSON]()
+
+```go
+func (r *OAuthStartResponse) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [OSSBucket]()
+
+
+
+```go
+type OSSBucket struct {
+ Name string `json:"name"`
+ Provider string `json:"provider"`
+ Region string `json:"region"`
+ Bucket string `json:"bucket"`
+ Prefix string `json:"prefix"`
+ Access string `json:"access"`
+ AcceleratorEndpoint string `json:"accelerator_endpoint"`
+ Credential OSSBucketCredential `json:"credential"`
+ JSON struct {
+ Name respjson.Field
+ Provider respjson.Field
+ Region respjson.Field
+ Bucket respjson.Field
+ Prefix respjson.Field
+ Access respjson.Field
+ AcceleratorEndpoint respjson.Field
+ Credential respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(OSSBucket\) [RawJSON]()
+
+```go
+func (r OSSBucket) RawJSON() string
+```
+
+
+
+
+### func \(\*OSSBucket\) [UnmarshalJSON]()
+
+```go
+func (r *OSSBucket) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [OSSBucketCredential]()
+
+OSSBucketCredential is the API read view. It contains no role ARN or secret.
+
+```go
+type OSSBucketCredential struct {
+ Type string `json:"type"`
+ AccessKeyID string `json:"access_key_id"`
+ JSON struct {
+ Type respjson.Field
+ AccessKeyID respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(OSSBucketCredential\) [RawJSON]()
+
+```go
+func (r OSSBucketCredential) RawJSON() string
+```
+
+
+
+
+### func \(\*OSSBucketCredential\) [UnmarshalJSON]()
+
+```go
+func (r *OSSBucketCredential) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [OSSBucketCredentialParam]()
+
+OSSBucketCredentialParam accepts ram\_role with RoleArn, or access\_key with ID and secret. A read\-view credential without secrets may be echoed to retain it on update.
+
+```go
+type OSSBucketCredentialParam struct {
+ Type string `json:"type" api:"required"`
+ RoleArn param.Opt[string] `json:"role_arn,omitzero"`
+ AccessKeyID param.Opt[string] `json:"access_key_id,omitzero"`
+ AccessKeySecret param.Opt[string] `json:"access_key_secret,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(OSSBucketCredentialParam\) [MarshalJSON]()
+
+```go
+func (r OSSBucketCredentialParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*OSSBucketCredentialParam\) [UnmarshalJSON]()
+
+```go
+func (r *OSSBucketCredentialParam) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [OSSBucketParam]()
+
+OSSBucketParam requires credentials for new buckets. Omit Credential on update to retain it.
+
+```go
+type OSSBucketParam struct {
+ Name string `json:"name" api:"required"`
+ Provider string `json:"provider" api:"required"`
+ Region string `json:"region" api:"required"`
+ Bucket string `json:"bucket" api:"required"`
+ Prefix param.Opt[string] `json:"prefix,omitzero"`
+ Access param.Opt[string] `json:"access,omitzero"`
+ AcceleratorEndpoint param.Opt[string] `json:"accelerator_endpoint,omitzero"`
+ Credential OSSBucketCredentialParam `json:"credential,omitzero"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(OSSBucketParam\) [MarshalJSON]()
+
+```go
+func (r OSSBucketParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*OSSBucketParam\) [UnmarshalJSON]()
+
+```go
+func (r *OSSBucketParam) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [OutputBehaviorCreateNew]()
@@ -55607,7 +56872,7 @@ List Sessions
func (r *SessionService) New(ctx context.Context, params SessionNewParams, opts ...option.RequestOption) (res *ManagedAgentsSession, err error)
```
-Create Session
+Create Session. Adds \_\_qca\_sdk\_ metadata; conflicting reserved values fail before sending.
### func \(\*SessionService\) [Search]()
@@ -59217,6 +60482,7 @@ Package convention implements Qoder authentication, transport, request options,
- [func DownloadFile\(ctx context.Context, path string, opts ...RequestOption\) \(\*http.Response, error\)](<#DownloadFile>)
- [func DownloadTo\(ctx context.Context, client \*http.Client, url string, destination io.Writer\) error](<#DownloadTo>)
- [func ExecuteNewRequest\(ctx context.Context, method string, u string, body any, dst any, opts ...RequestOption\) error](<#ExecuteNewRequest>)
+- [func ExecuteNewSessionRequest\(ctx context.Context, method string, u string, body any, dst any, opts ...RequestOption\) error](<#ExecuteNewSessionRequest>)
- [func NewCredentialTransport\(credential Credential, next http.RoundTripper\) http.RoundTripper](<#NewCredentialTransport>)
- [type APIResponse](<#APIResponse>)
- [func NewAPIResponse\(r \*http.Response\) \*APIResponse](<#NewAPIResponse>)
@@ -59314,6 +60580,15 @@ func ExecuteNewRequest(ctx context.Context, method string, u string, body any, d
+
+## func [ExecuteNewSessionRequest]()
+
+```go
+func ExecuteNewSessionRequest(ctx context.Context, method string, u string, body any, dst any, opts ...RequestOption) error
+```
+
+ExecuteNewSessionRequest adds SDK provenance to a Session creation request after request options have been applied. Conflicting reserved metadata fails before transport; caller\-owned params and metadata are never modified.
+
## func [NewCredentialTransport]()
diff --git a/examples/forward/memory/main.go b/examples/forward/memory/main.go
index 7ad1956..7199352 100644
--- a/examples/forward/memory/main.go
+++ b/examples/forward/memory/main.go
@@ -103,7 +103,7 @@ func run(ctx context.Context, r *live.Run, s *forwardutil.Example) error {
return err
})
r.Step("查询绑定,确认记忆库已关联")
- mounts, err := s.Client.Identities.MemoryStores.List(ctx, identity.ID, template)
+ mounts, err := s.Client.Identities.MemoryStores.List(ctx, identity.ID, template, forward.IdentityMemoryStoreListParams{})
if err != nil {
return err
}
diff --git a/forward/channelpairing.go b/forward/channelpairing.go
index 9ff8632..8c52f3a 100644
--- a/forward/channelpairing.go
+++ b/forward/channelpairing.go
@@ -9,7 +9,9 @@ import (
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apijson"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apiquery"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/option"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/pagination"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/respjson"
)
@@ -127,3 +129,70 @@ type ChannelPairing struct {
func (r ChannelPairing) RawJSON() string { return r.JSON.raw }
func (r *ChannelPairing) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+func (r *ChannelPairingService) Get(ctx context.Context, pairingID string, opts ...option.RequestOption) (res *ChannelPairing, err error) {
+ if pairingID == "" {
+ return nil, fmt.Errorf("missing required pairing_id parameter")
+ }
+ opts = slices.Concat(r.Options, opts)
+ err = convention.ExecuteNewRequest(ctx, http.MethodGet, fmt.Sprintf("channel_pairings/%s", url.PathEscape(pairingID)), nil, &res, opts...)
+ return res, err
+}
+
+// Update changes an active binding. Supply at least one nonempty field.
+func (r *ChannelPairingService) Update(ctx context.Context, pairingID string, params ChannelPairingUpdateParams, opts ...option.RequestOption) (res *ChannelPairing, err error) {
+ if pairingID == "" {
+ return nil, fmt.Errorf("missing required pairing_id parameter")
+ }
+ opts = slices.Concat(r.Options, opts)
+ err = convention.ExecuteNewRequest(ctx, http.MethodPost, fmt.Sprintf("channel_pairings/%s", url.PathEscape(pairingID)), params, &res, opts...)
+ return res, err
+}
+func (r *ChannelPairingService) List(ctx context.Context, params ChannelPairingListParams, opts ...option.RequestOption) (res *pagination.Page[ChannelPairing], err error) {
+ opts = slices.Concat(r.Options, opts)
+ var raw *http.Response
+ opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
+ cfg, err := convention.NewRequestConfig(ctx, http.MethodGet, "channel_pairings", params, &res, opts...)
+ if err != nil {
+ return nil, err
+ }
+ if err = cfg.Execute(); err != nil {
+ return nil, err
+ }
+ res.SetPageConfig(cfg, raw)
+ return res, nil
+}
+func (r *ChannelPairingService) ListAutoPaging(ctx context.Context, params ChannelPairingListParams, opts ...option.RequestOption) *pagination.PageAutoPager[ChannelPairing] {
+ return pagination.NewPageAutoPager(r.List(ctx, params, opts...))
+}
+
+type ChannelPairingUpdateParams struct {
+ IdentityID param.Opt[string] `json:"identity_id,omitzero"`
+ TemplateID param.Opt[string] `json:"template_id,omitzero"`
+ paramObj
+}
+
+func (r ChannelPairingUpdateParams) MarshalJSON() ([]byte, error) {
+ type shadow ChannelPairingUpdateParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *ChannelPairingUpdateParams) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type ChannelPairingListParams struct {
+ ChannelID param.Opt[string] `query:"channel_id,omitzero" json:"-"`
+ Status param.Opt[string] `query:"status,omitzero" json:"-"`
+ TargetType param.Opt[string] `query:"target_type,omitzero" json:"-"`
+ TargetExternalID param.Opt[string] `query:"target_external_id,omitzero" json:"-"`
+ IdentityID param.Opt[string] `query:"identity_id,omitzero" json:"-"`
+ TemplateID param.Opt[string] `query:"template_id,omitzero" json:"-"`
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
+ BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
+ paramObj
+}
+
+func (r ChannelPairingListParams) URLQuery() (url.Values, error) {
+ return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{})
+}
diff --git a/forward/client.go b/forward/client.go
index 006a58a..0782c12 100644
--- a/forward/client.go
+++ b/forward/client.go
@@ -12,6 +12,7 @@ const DefaultBaseURL = "https://api.qoder.com/api/v1/forward/"
// Client exposes Forward resources. Configure options before sharing a client.
type Client struct {
+ Dreams DreamService
Webhooks WebhookService
Options []option.RequestOption
Templates TemplateService
@@ -47,6 +48,7 @@ func NewClient(opts ...option.RequestOption) Client {
defaults = append(defaults, convention.EnvironmentAuthentication())
opts = slices.Concat(defaults, opts)
return Client{Options: opts,
+ Dreams: NewDreamService(opts...),
Webhooks: NewWebhookService(opts...),
Templates: NewTemplateService(opts...),
Identities: NewIdentityService(opts...),
diff --git a/forward/client_test.go b/forward/client_test.go
index 517596e..83d8473 100644
--- a/forward/client_test.go
+++ b/forward/client_test.go
@@ -34,8 +34,8 @@ func TestForwardAPIInventory(t *testing.T) {
}
}
walk(root)
- if len(actual) != 138 {
- t.Fatalf("HTTP methods: %d want 138", len(actual))
+ if len(actual) != 146 {
+ t.Fatalf("HTTP methods: %d want 146", len(actual))
}
baseline := map[string]bool{}
for _, c := range operations(t) {
diff --git a/forward/configuration_types.go b/forward/configuration_types.go
index a0f7781..329802b 100644
--- a/forward/configuration_types.go
+++ b/forward/configuration_types.go
@@ -1,6 +1,8 @@
package forward
import (
+ "encoding/json"
+ "fmt"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apijson"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/respjson"
@@ -223,10 +225,13 @@ func (r SkillBindingParam) MarshalJSON() ([]byte, error) {
func (r *SkillBindingParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type MultiagentEntry struct {
+ OfString string `json:"-"`
+ Model string `json:"model"`
Type string `json:"type" api:"required"`
TemplateID string `json:"template_id"`
Name string `json:"name"`
JSON struct {
+ Model respjson.Field
Type respjson.Field
TemplateID respjson.Field
Name respjson.Field
@@ -235,10 +240,22 @@ type MultiagentEntry struct {
} `json:"-"`
}
-func (r MultiagentEntry) RawJSON() string { return r.JSON.raw }
-func (r *MultiagentEntry) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+// UnmarshalAPIJSON keeps string roster entries intact when nested in a Template.
+func (r *MultiagentEntry) UnmarshalAPIJSON(data []byte) error { return r.UnmarshalJSON(data) }
+
+func (r MultiagentEntry) RawJSON() string { return r.JSON.raw }
+func (r *MultiagentEntry) UnmarshalJSON(data []byte) error {
+ *r = MultiagentEntry{}
+ if len(data) > 0 && data[0] == '"' {
+ r.JSON.raw = string(data)
+ return json.Unmarshal(data, &r.OfString)
+ }
+ return apijson.UnmarshalRoot(data, r)
+}
type MultiagentEntryParam struct {
+ OfString param.Opt[string] `json:"-"`
+ Model param.Opt[string] `json:"model,omitzero"`
Type string `json:"type" api:"required"`
TemplateID param.Opt[string] `json:"template_id,omitzero"`
Name param.Opt[string] `json:"name,omitzero"`
@@ -246,10 +263,27 @@ type MultiagentEntryParam struct {
}
func (r MultiagentEntryParam) MarshalJSON() ([]byte, error) {
+ if r.OfString.Valid() {
+ if r.Type != "" || r.Model.Valid() || r.TemplateID.Valid() || r.Name.Valid() {
+ return nil, fmt.Errorf("multiagent entry must be either a template ID or an object")
+ }
+ return json.Marshal(r.OfString.Value)
+ }
type shadow MultiagentEntryParam
return param.MarshalObject(r, (*shadow)(&r))
}
+func (r *MultiagentEntryParam) UnmarshalAPIJSON(data []byte) error { return r.UnmarshalJSON(data) }
+
func (r *MultiagentEntryParam) UnmarshalJSON(data []byte) error {
+ *r = MultiagentEntryParam{}
+ if len(data) > 0 && data[0] == '"' {
+ var id string
+ if err := json.Unmarshal(data, &id); err != nil {
+ return err
+ }
+ *r = MultiagentEntryParam{OfString: String(id)}
+ return nil
+ }
return apijson.UnmarshalRoot(data, r)
}
@@ -522,9 +556,10 @@ func (r SkillOverrideParam) MarshalJSON() ([]byte, error) {
func (r *SkillOverrideParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type IdentityConfigSpec struct {
+ ManagedToolConfig map[string]*ManagedCapabilityOverride `json:"managed_tool_config"`
System SystemOverride `json:"system"`
Model ModelConfig `json:"model"`
- Tools map[string]ToolOverride `json:"tools"`
+ Tools IdentityToolsUnion `json:"tools"`
MCPServers map[string]MCPServerOverride `json:"mcp_servers"`
Skills map[string]SkillOverride `json:"skills"`
Toolsets map[string]any `json:"toolsets"`
@@ -534,6 +569,7 @@ type IdentityConfigSpec struct {
GitHubRepositories map[string]GitHubRepository `json:"github_repositories"`
EnvironmentVariables map[string]EnvironmentVariableOverride `json:"environment_variables"`
JSON struct {
+ ManagedToolConfig respjson.Field
System respjson.Field
Model respjson.Field
Tools respjson.Field
@@ -554,9 +590,10 @@ func (r IdentityConfigSpec) RawJSON() string { return r.JSON.ra
func (r *IdentityConfigSpec) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type IdentityConfigSpecParam struct {
+ ManagedToolConfig map[string]ManagedCapabilityOverrideParam `json:"managed_tool_config,omitzero"`
System SystemOverrideParam `json:"system,omitzero"`
Model ModelConfigUnionParam `json:"model,omitzero"`
- Tools map[string]ToolOverrideParam `json:"tools,omitzero"`
+ Tools IdentityToolsUnionParam `json:"tools,omitzero"`
MCPServers map[string]MCPServerOverrideParam `json:"mcp_servers,omitzero"`
Skills map[string]SkillOverrideParam `json:"skills,omitzero"`
Toolsets map[string]any `json:"toolsets,omitzero"`
@@ -585,7 +622,7 @@ type SessionEventParam struct {
DenyMessage param.Opt[string] `json:"deny_message,omitzero"`
IsError param.Opt[bool] `json:"is_error,omitzero"`
Description param.Opt[string] `json:"description,omitzero"`
- Rubric param.Opt[string] `json:"rubric,omitzero"`
+ Rubric OutcomeRubricParam `json:"rubric,omitzero"`
OutcomeID param.Opt[string] `json:"outcome_id,omitzero"`
MaxIterations param.Opt[int64] `json:"max_iterations,omitzero"`
paramObj
@@ -623,3 +660,61 @@ func (r ManagedToolConfigParam) MarshalJSON() ([]byte, error) {
func (r *ManagedToolConfigParam) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+
+// IdentityToolsUnionParam overrides individual tools or replaces the complete tools array.
+type IdentityToolsUnionParam struct {
+ OfOverrides map[string]ToolOverrideParam `json:",omitzero,inline"`
+ OfArray []ToolParam `json:",omitzero,inline"`
+ paramUnion
+}
+
+func (r IdentityToolsUnionParam) MarshalJSON() ([]byte, error) {
+ return param.MarshalUnion(r, r.OfOverrides, r.OfArray)
+}
+func (r *IdentityToolsUnionParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type IdentityToolsUnion struct {
+ OfOverrides map[string]*ToolOverride
+ OfArray []Tool
+ raw string
+}
+
+func (r IdentityToolsUnion) RawJSON() string { return r.raw }
+func (r *IdentityToolsUnion) UnmarshalJSON(data []byte) error {
+ *r = IdentityToolsUnion{raw: string(data)}
+ if len(data) > 0 && data[0] == '[' {
+ return json.Unmarshal(data, &r.OfArray)
+ }
+ return json.Unmarshal(data, &r.OfOverrides)
+}
+
+// ManagedCapabilityOverrideParam is a sparse Identity capability switch.
+// Use param.NullStruct to restore inheritance for one selector.
+type ManagedCapabilityOverrideParam struct {
+ Enabled bool `json:"enabled" api:"required"`
+ paramObj
+}
+
+func (r ManagedCapabilityOverrideParam) MarshalJSON() ([]byte, error) {
+ type shadow ManagedCapabilityOverrideParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *ManagedCapabilityOverrideParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type ManagedCapabilityOverride struct {
+ Enabled bool `json:"enabled"`
+ JSON struct {
+ Enabled respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r ManagedCapabilityOverride) RawJSON() string { return r.JSON.raw }
+func (r *ManagedCapabilityOverride) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
diff --git a/forward/dream.go b/forward/dream.go
new file mode 100644
index 0000000..7a52f95
--- /dev/null
+++ b/forward/dream.go
@@ -0,0 +1,262 @@
+package forward
+
+import (
+ "context"
+ "fmt"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apijson"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apiquery"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/option"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/pagination"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/respjson"
+ "net/http"
+ "net/url"
+ "slices"
+ "time"
+)
+
+// DreamService consolidates Forward memory; requires PAT or an admin SAT.
+type DreamService struct{ Options []option.RequestOption }
+
+func NewDreamService(opts ...option.RequestOption) DreamService {
+ return DreamService{Options: slices.Clone(opts)}
+}
+func (r *DreamService) New(ctx context.Context, params DreamNewParams, opts ...option.RequestOption) (res *Dream, err error) {
+ opts = slices.Concat(r.Options, opts)
+ err = convention.ExecuteNewRequest(ctx, http.MethodPost, "dreams", params, &res, opts...)
+ return res, err
+}
+func (r *DreamService) List(ctx context.Context, params DreamListParams, opts ...option.RequestOption) (res *pagination.Page[Dream], err error) {
+ opts = slices.Concat(r.Options, opts)
+ var raw *http.Response
+ opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
+ cfg, err := convention.NewRequestConfig(ctx, http.MethodGet, "dreams", params, &res, opts...)
+ if err != nil {
+ return nil, err
+ }
+ if err = cfg.Execute(); err != nil {
+ return nil, err
+ }
+ res.SetPageConfig(cfg, raw)
+ return res, nil
+}
+func (r *DreamService) ListAutoPaging(ctx context.Context, params DreamListParams, opts ...option.RequestOption) *pagination.PageAutoPager[Dream] {
+ return pagination.NewPageAutoPager(r.List(ctx, params, opts...))
+}
+func (r *DreamService) Get(ctx context.Context, dreamID string, opts ...option.RequestOption) (res *Dream, err error) {
+ if dreamID == "" {
+ return nil, fmt.Errorf("missing required dream_id parameter")
+ }
+ opts = slices.Concat(r.Options, opts)
+ path := fmt.Sprintf("dreams/%s", url.PathEscape(dreamID))
+ err = convention.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
+ return res, err
+}
+func (r *DreamService) Cancel(ctx context.Context, dreamID string, opts ...option.RequestOption) (res *Dream, err error) {
+ if dreamID == "" {
+ return nil, fmt.Errorf("missing required dream_id parameter")
+ }
+ opts = slices.Concat(r.Options, opts)
+ path := fmt.Sprintf("dreams/%s/cancel", url.PathEscape(dreamID))
+ err = convention.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
+ return res, err
+}
+func (r *DreamService) Archive(ctx context.Context, dreamID string, opts ...option.RequestOption) (res *Dream, err error) {
+ if dreamID == "" {
+ return nil, fmt.Errorf("missing required dream_id parameter")
+ }
+ opts = slices.Concat(r.Options, opts)
+ path := fmt.Sprintf("dreams/%s/archive", url.PathEscape(dreamID))
+ err = convention.ExecuteNewRequest(ctx, http.MethodPost, path, nil, &res, opts...)
+ return res, err
+}
+
+type DreamListParams struct {
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
+ BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
+ IncludeArchived param.Opt[bool] `query:"include_archived,omitzero" json:"-"`
+ paramObj
+}
+
+func (r DreamListParams) URLQuery() (url.Values, error) {
+ return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{})
+}
+
+type DreamNewParams struct {
+ Inputs []DreamInputParam `json:"inputs,omitzero"`
+ Model DreamNewParamsModelUnion `json:"model,omitzero"`
+ Instructions param.Opt[string] `json:"instructions,omitzero"`
+ paramObj
+}
+
+func (r DreamNewParams) MarshalJSON() ([]byte, error) {
+ type shadow DreamNewParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *DreamNewParams) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type DreamInputParam struct {
+ Type string `json:"type"`
+ MemoryStoreID param.Opt[string] `json:"memory_store_id,omitzero"`
+ IdentityID param.Opt[string] `json:"identity_id,omitzero"`
+ TemplateID param.Opt[string] `json:"template_id,omitzero"`
+ SessionIDs []string `json:"session_ids,omitzero"`
+ paramObj
+}
+
+func (r DreamInputParam) MarshalJSON() ([]byte, error) {
+ type shadow DreamInputParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *DreamInputParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type DreamModelConfigParam struct {
+ ID string `json:"id"`
+ Effort param.Opt[string] `json:"effort,omitzero"`
+ ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
+ paramObj
+}
+
+func (r DreamModelConfigParam) MarshalJSON() ([]byte, error) {
+ type shadow DreamModelConfigParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *DreamModelConfigParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+// DreamNewParamsModelUnion accepts a model ID or tuning object; omit to use auto.
+type DreamNewParamsModelUnion struct {
+ OfString param.Opt[string] `json:",omitzero,inline"`
+ OfConfig *DreamModelConfigParam `json:",omitzero,inline"`
+ paramUnion
+}
+
+func (r DreamNewParamsModelUnion) MarshalJSON() ([]byte, error) {
+ return param.MarshalUnion(r, r.OfString, r.OfConfig)
+}
+func (r *DreamNewParamsModelUnion) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type Dream struct {
+ ID string `json:"id"`
+ Type string `json:"type"`
+ Status string `json:"status"`
+ Inputs []DreamInput `json:"inputs"`
+ Outputs []DreamOutput `json:"outputs"`
+ Model DreamModelConfig `json:"model"`
+ Instructions string `json:"instructions"`
+ Usage DreamUsage `json:"usage"`
+ Error DreamError `json:"error"`
+ CreatedAt time.Time `json:"created_at"`
+ EndedAt time.Time `json:"ended_at"`
+ ArchivedAt time.Time `json:"archived_at"`
+ JSON struct {
+ ID respjson.Field
+ Type respjson.Field
+ Status respjson.Field
+ Inputs respjson.Field
+ Outputs respjson.Field
+ Model respjson.Field
+ Instructions respjson.Field
+ Usage respjson.Field
+ Error respjson.Field
+ CreatedAt respjson.Field
+ EndedAt respjson.Field
+ ArchivedAt respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r Dream) RawJSON() string { return r.JSON.raw }
+func (r *Dream) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type DreamInput struct {
+ Type string `json:"type"`
+ MemoryStoreID string `json:"memory_store_id"`
+ IdentityID string `json:"identity_id"`
+ TemplateID string `json:"template_id"`
+ SessionIDs []string `json:"session_ids"`
+ JSON struct {
+ Type respjson.Field
+ MemoryStoreID respjson.Field
+ IdentityID respjson.Field
+ TemplateID respjson.Field
+ SessionIDs respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r DreamInput) RawJSON() string { return r.JSON.raw }
+func (r *DreamInput) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type DreamOutput struct {
+ Type string `json:"type"`
+ MemoryStoreID string `json:"memory_store_id"`
+ FilesTouched []string `json:"files_touched"`
+ JSON struct {
+ Type respjson.Field
+ MemoryStoreID respjson.Field
+ FilesTouched respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r DreamOutput) RawJSON() string { return r.JSON.raw }
+func (r *DreamOutput) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type DreamModelConfig struct {
+ ID string `json:"id"`
+ Effort string `json:"effort"`
+ ContextWindow int64 `json:"context_window"`
+ JSON struct {
+ ID respjson.Field
+ Effort respjson.Field
+ ContextWindow respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r DreamModelConfig) RawJSON() string { return r.JSON.raw }
+func (r *DreamModelConfig) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type DreamUsage struct {
+ InputTokens int64 `json:"input_tokens"`
+ OutputTokens int64 `json:"output_tokens"`
+ CacheCreationInputTokens int64 `json:"cache_creation_input_tokens"`
+ CacheReadInputTokens int64 `json:"cache_read_input_tokens"`
+ JSON struct {
+ InputTokens respjson.Field
+ OutputTokens respjson.Field
+ CacheCreationInputTokens respjson.Field
+ CacheReadInputTokens respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r DreamUsage) RawJSON() string { return r.JSON.raw }
+func (r *DreamUsage) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type DreamError struct {
+ Type string `json:"type"`
+ Code string `json:"code"`
+ Message string `json:"message"`
+ JSON struct {
+ Type respjson.Field
+ Code respjson.Field
+ Message respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r DreamError) RawJSON() string { return r.JSON.raw }
+func (r *DreamError) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
diff --git a/forward/identity.go b/forward/identity.go
index 6c0997a..3d98973 100644
--- a/forward/identity.go
+++ b/forward/identity.go
@@ -85,6 +85,7 @@ func (r *IdentityService) New(ctx context.Context, params IdentityNewParams, opt
}
type IdentityNewParams struct {
+ AutoMemoryStore param.Opt[bool] `json:"auto_memory_store,omitzero"`
// End-user ID in the integrator's system; cannot be empty or whitespace only.
ExternalID string `json:"external_id" api:"required"`
// Display name; when provided it cannot be empty or whitespace only.
@@ -149,6 +150,7 @@ func (r *IdentityService) Update(ctx context.Context, identityID string, params
}
type IdentityUpdateParams struct {
+ AutoMemoryStore param.Opt[bool] `json:"auto_memory_store,omitzero"`
// Replaces the existing end-user ID.
ExternalID param.Opt[string] `json:"external_id,omitzero"`
// Replaces the display name.
@@ -347,6 +349,7 @@ func (r IdentityStats) RawJSON() string { return r.JSON.raw }
func (r *IdentityStats) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type Identity struct {
+ AutoMemoryStore bool `json:"auto_memory_store"`
// Forward Identity ID; the `idn_` prefix is recommended.
ID string `json:"id"`
// End-user ID in the integrator's system.
@@ -364,16 +367,17 @@ type Identity struct {
// Last update time, in RFC 3339 format.
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
JSON struct {
- ID respjson.Field
- ExternalID respjson.Field
- Name respjson.Field
- IdentityType respjson.Field
- Enabled respjson.Field
- Metadata respjson.Field
- CreatedAt respjson.Field
- UpdatedAt respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
+ AutoMemoryStore respjson.Field
+ ID respjson.Field
+ ExternalID respjson.Field
+ Name respjson.Field
+ IdentityType respjson.Field
+ Enabled respjson.Field
+ Metadata respjson.Field
+ CreatedAt respjson.Field
+ UpdatedAt respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
} `json:"-"`
}
diff --git a/forward/identitymemorystore.go b/forward/identitymemorystore.go
index 09f8a5a..65e6124 100644
--- a/forward/identitymemorystore.go
+++ b/forward/identitymemorystore.go
@@ -10,7 +10,9 @@ import (
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apijson"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apiquery"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/option"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/pagination"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
"github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/respjson"
)
@@ -25,7 +27,7 @@ func NewIdentityMemoryStoreService(opts ...option.RequestOption) IdentityMemoryS
}
// List Memory Store mounts on an Identity
-func (r *IdentityMemoryStoreService) List(ctx context.Context, identityID string, templateID string, opts ...option.RequestOption) (res *IdentityMemoryStoreListResponse, err error) {
+func (r *IdentityMemoryStoreService) List(ctx context.Context, identityID string, templateID string, params IdentityMemoryStoreListParams, opts ...option.RequestOption) (res *pagination.Page[MemoryStoreMount], err error) {
if identityID == "" {
return nil, fmt.Errorf("missing required identity_id parameter")
}
@@ -35,8 +37,17 @@ func (r *IdentityMemoryStoreService) List(ctx context.Context, identityID string
opts = slices.Concat(r.Options, opts)
path := fmt.Sprintf("identities/%s/templates/%s/memory_stores", url.PathEscape(identityID), url.PathEscape(templateID))
- err = convention.ExecuteNewRequest(ctx, http.MethodGet, path, nil, &res, opts...)
- return res, err
+ var raw *http.Response
+ opts = append([]option.RequestOption{option.WithResponseInto(&raw)}, opts...)
+ cfg, err := convention.NewRequestConfig(ctx, http.MethodGet, path, params, &res, opts...)
+ if err != nil {
+ return nil, err
+ }
+ if err = cfg.Execute(); err != nil {
+ return nil, err
+ }
+ res.SetPageConfig(cfg, raw)
+ return res, nil
}
// Mount Memory Store on an Identity
@@ -55,6 +66,7 @@ func (r *IdentityMemoryStoreService) Mount(ctx context.Context, identityID strin
}
type IdentityMemoryStoreMountParams struct {
+ Access param.Opt[string] `json:"access,omitzero"`
// ID of the Memory Store to mount (`memstore_...`). It must be an active Store
// visible to the caller.
MemoryStoreID string `json:"memory_store_id" api:"required"`
@@ -139,9 +151,13 @@ func (r MemoryStoreMount) RawJSON() string { return r.JSON.raw
func (r *MemoryStoreMount) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type IdentityMemoryStoreListResponse struct {
+ FirstID string `json:"first_id"`
+ LastID string `json:"last_id"`
Data []MemoryStoreMount `json:"data"`
HasMore bool `json:"has_more"`
JSON struct {
+ FirstID respjson.Field
+ LastID respjson.Field
Data respjson.Field
HasMore respjson.Field
ExtraFields map[string]respjson.Field
@@ -153,3 +169,17 @@ func (r IdentityMemoryStoreListResponse) RawJSON() string { return r.JSON.raw }
func (r *IdentityMemoryStoreListResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+
+type IdentityMemoryStoreListParams struct {
+ Limit param.Opt[int64] `query:"limit,omitzero" json:"-"`
+ AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
+ BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
+ paramObj
+}
+
+func (r IdentityMemoryStoreListParams) URLQuery() (url.Values, error) {
+ return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{})
+}
+func (r *IdentityMemoryStoreService) ListAutoPaging(ctx context.Context, identityID, templateID string, params IdentityMemoryStoreListParams, opts ...option.RequestOption) *pagination.PageAutoPager[MemoryStoreMount] {
+ return pagination.NewPageAutoPager(r.List(ctx, identityID, templateID, params, opts...))
+}
diff --git a/forward/identitymemorystore_test.go b/forward/identitymemorystore_test.go
index 8d3230f..d303aff 100644
--- a/forward/identitymemorystore_test.go
+++ b/forward/identitymemorystore_test.go
@@ -12,7 +12,7 @@ func TestIdentityMemoryStoreAPIContracts(t *testing.T) {
for _, status := range []int{200, 400} {
t.Run(statusName(status), func(t *testing.T) {
client := contractClient(t, "listMemoryStoreMounts", status)
- res, err := client.Identities.MemoryStores.List(context.Background(), pathSegment, pathSegment)
+ res, err := client.Identities.MemoryStores.List(context.Background(), pathSegment, pathSegment, contractParams[forward.IdentityMemoryStoreListParams](t, "listMemoryStoreMounts"))
checkError(t, status, err)
if status == 200 {
checkDecoded(t, res)
diff --git a/forward/memorystore_live_test.go b/forward/memorystore_live_test.go
index 05a1d1b..3b7b02d 100644
--- a/forward/memorystore_live_test.go
+++ b/forward/memorystore_live_test.go
@@ -36,6 +36,6 @@ func TestMemoryStoreAndMemoryLifecycleLive(t *testing.T) {
_, err := s.client.Identities.MemoryStores.Detach(ctx, identity.ID, template.ID, store.ID)
return err
})
- _, err = s.client.Identities.MemoryStores.List(ctx, identity.ID, template.ID)
+ _, err = s.client.Identities.MemoryStores.List(ctx, identity.ID, template.ID, forward.IdentityMemoryStoreListParams{})
liveCheck(t, err)
}
diff --git a/forward/official_contract_test.go b/forward/official_contract_test.go
new file mode 100644
index 0000000..5bab9df
--- /dev/null
+++ b/forward/official_contract_test.go
@@ -0,0 +1,215 @@
+package forward_test
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
+ "io"
+ "net/http"
+ "reflect"
+ "testing"
+)
+
+func TestOfficialOutcomeRubricContract(t *testing.T) {
+ for _, rubric := range []forward.OutcomeRubricParam{{Type: "text", Content: forward.String("report exists")}, {Type: "file", FileID: forward.String("file_test")}} {
+ wire, err := json.Marshal(forward.SessionEventParam{Type: "user.define_outcome", Rubric: rubric})
+ if err != nil {
+ t.Fatal(err)
+ }
+ var event forward.SessionEvent
+ if err = json.Unmarshal(wire, &event); err != nil {
+ t.Fatal(err)
+ }
+ if !event.JSON.Rubric.Valid() || event.Rubric.Type != rubric.Type {
+ t.Fatalf("invalid rubric: %+v", event)
+ }
+ if rubric.Type == "text" && event.Rubric.Content != "report exists" {
+ t.Fatal(event.Rubric)
+ }
+ if rubric.Type == "file" && event.Rubric.FileID != "file_test" {
+ t.Fatal(event.Rubric)
+ }
+ }
+}
+
+func TestOfficialNewAPIContracts(t *testing.T) {
+ for _, tc := range []struct {
+ id string
+ call func(forward.Client) (any, error)
+ }{
+ {"createDream", func(c forward.Client) (any, error) {
+ return c.Dreams.New(context.Background(), contractParams[forward.DreamNewParams](t, "createDream"))
+ }},
+ {"listDreams", func(c forward.Client) (any, error) {
+ return c.Dreams.List(context.Background(), contractParams[forward.DreamListParams](t, "listDreams"))
+ }},
+ {"getDream", func(c forward.Client) (any, error) { return c.Dreams.Get(context.Background(), pathSegment) }},
+ {"cancelDream", func(c forward.Client) (any, error) { return c.Dreams.Cancel(context.Background(), pathSegment) }},
+ {"archiveDream", func(c forward.Client) (any, error) { return c.Dreams.Archive(context.Background(), pathSegment) }},
+ {"listChannelPairings", func(c forward.Client) (any, error) {
+ return c.ChannelPairings.List(context.Background(), contractParams[forward.ChannelPairingListParams](t, "listChannelPairings"))
+ }},
+ {"getChannelPairing", func(c forward.Client) (any, error) { return c.ChannelPairings.Get(context.Background(), pathSegment) }},
+ {"updateChannelPairing", func(c forward.Client) (any, error) {
+ return c.ChannelPairings.Update(context.Background(), pathSegment, contractParams[forward.ChannelPairingUpdateParams](t, "updateChannelPairing"))
+ }},
+ } {
+ t.Run(tc.id, func(t *testing.T) {
+ res, err := tc.call(contractClient(t, tc.id, 200))
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkDecoded(t, res)
+ })
+ }
+}
+
+func TestOfficialIdentityNullAndArrayOverrides(t *testing.T) {
+ for _, tc := range []struct {
+ spec forward.IdentityConfigSpecParam
+ want string
+ }{
+ {forward.IdentityConfigSpecParam{Tools: forward.IdentityToolsUnionParam{OfArray: []forward.ToolParam{}}}, `{"tools":[]}`},
+ {forward.IdentityConfigSpecParam{Tools: forward.IdentityToolsUnionParam{OfOverrides: map[string]forward.ToolOverrideParam{"Bash": {Enabled: forward.Bool(false)}}}}, `{"tools":{"Bash":{"enabled":false}}}`},
+ {forward.IdentityConfigSpecParam{Tools: param.NullStruct[forward.IdentityToolsUnionParam](), ManagedToolConfig: param.NullMap[map[string]forward.ManagedCapabilityOverrideParam]()}, `{"tools":null,"managed_tool_config":null}`},
+ {forward.IdentityConfigSpecParam{ManagedToolConfig: map[string]forward.ManagedCapabilityOverrideParam{"schedule": {Enabled: false}, "drive": param.NullStruct[forward.ManagedCapabilityOverrideParam]()}}, `{"managed_tool_config":{"schedule":{"enabled":false},"drive":null}}`},
+ } {
+ var want any
+ _ = json.Unmarshal([]byte(tc.want), &want)
+ body, err := json.Marshal(tc.spec)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var got any
+ _ = json.Unmarshal(body, &got)
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("got %s want %s", body, tc.want)
+ }
+ var spec forward.IdentityConfigSpec
+ if err = json.Unmarshal(body, &spec); err != nil {
+ t.Fatal(err)
+ }
+ }
+ var roster forward.MultiagentConfig
+ raw := `{"type":"roster","agents":["tmpl_helper",{"type":"advisor","model":"ultimate"},{"type":"self"}]}`
+ if err := json.Unmarshal([]byte(raw), &roster); err != nil {
+ t.Fatal(err)
+ }
+ if roster.Agents[0].OfString != "tmpl_helper" || roster.Agents[1].Model != "ultimate" {
+ t.Fatal(roster)
+ }
+ var params forward.MultiagentConfigParam
+ if err := json.Unmarshal([]byte(raw), ¶ms); err != nil {
+ t.Fatal(err)
+ }
+ body, err := json.Marshal(params)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var got, want any
+ _ = json.Unmarshal(body, &got)
+ _ = json.Unmarshal([]byte(raw), &want)
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("roster: %s", body)
+ }
+}
+
+func TestOfficialMountPaginationRetainsScope(t *testing.T) {
+ for _, reverse := range []bool{false, true} {
+ calls := 0
+ key := "after_id"
+ if reverse {
+ key = "before_id"
+ }
+ client := testClient(func(r *http.Request) (*http.Response, error) {
+ calls++
+ q := r.URL.Query()
+ if r.URL.Path != "/api/v1/forward/identities/idn/templates/tmpl/memory_stores" || q.Get("limit") != "1" {
+ t.Fatal(r.URL)
+ }
+ want := "start"
+ if calls == 2 {
+ want = "mem_one"
+ }
+ if q.Get(key) != want {
+ t.Fatal(r.URL)
+ }
+ id := "mem_one"
+ more := true
+ if calls == 2 {
+ id = "mem_two"
+ more = false
+ }
+ return reply(r, 200, fmt.Sprintf(`{"data":[{"memory_store_id":%q,"access":"read_write"}],"first_id":%q,"last_id":%q,"has_more":%t}`, id, id, id, more)), nil
+ })
+ p := forward.IdentityMemoryStoreListParams{Limit: forward.Int(1)}
+ if reverse {
+ p.BeforeID = forward.String("start")
+ } else {
+ p.AfterID = forward.String("start")
+ }
+ pager := client.Identities.MemoryStores.ListAutoPaging(context.Background(), "idn", "tmpl", p)
+ var ids []string
+ for pager.Next() {
+ ids = append(ids, pager.Current().MemoryStoreID)
+ }
+ if pager.Err() != nil || !reflect.DeepEqual(ids, []string{"mem_one", "mem_two"}) || calls != 2 {
+ t.Fatalf("%v %v calls=%d", ids, pager.Err(), calls)
+ }
+ }
+}
+
+func TestOfficialForwardParameterPlacement(t *testing.T) {
+ client := testClient(func(r *http.Request) (*http.Response, error) {
+ var body []byte
+ if r.Body != nil {
+ body, _ = io.ReadAll(r.Body)
+ }
+ switch r.URL.Path {
+ case "/api/v1/forward/identities/idn":
+ if string(body) != `{"auto_memory_store":false}` {
+ t.Fatal(string(body))
+ }
+ return reply(r, 200, `{"id":"idn","auto_memory_store":false}`), nil
+ case "/api/v1/forward/identities/idn/templates/tmpl/memory_stores":
+ var b map[string]any
+ _ = json.Unmarshal(body, &b)
+ if b["access"] != "read_write" || b["memory_store_id"] != "mem" {
+ t.Fatal(b)
+ }
+ return reply(r, 200, `{"memory_store_id":"mem","access":"read_write"}`), nil
+ case "/api/v1/forward/schedules/sched":
+ var b map[string]any
+ _ = json.Unmarshal(body, &b)
+ if len(b) != 1 || b["resources"] == nil {
+ t.Fatal(b)
+ }
+ return reply(r, 200, `{"resources":[{"type":"file","file_id":"file_test","mount_path":"/data/test.txt"}]}`), nil
+ case "/api/v1/forward/schedule_runs/run":
+ if r.URL.Query().Get("include_initial_events") != "true" || len(body) != 0 {
+ t.Fatalf("%s %s", r.URL, body)
+ }
+ return reply(r, 200, `{"initial_events":[{"type":"user.message","content":[{"type":"text","text":"run input"}]}]}`), nil
+ }
+ t.Fatal(r.URL)
+ return nil, nil
+ })
+ ctx := context.Background()
+ id, err := client.Identities.Update(ctx, "idn", forward.IdentityUpdateParams{AutoMemoryStore: forward.Bool(false)})
+ if err != nil || !id.JSON.AutoMemoryStore.Valid() || id.AutoMemoryStore {
+ t.Fatalf("%+v %v", id, err)
+ }
+ if _, err = client.Identities.MemoryStores.Mount(ctx, "idn", "tmpl", forward.IdentityMemoryStoreMountParams{MemoryStoreID: "mem", Access: forward.String("read_write")}); err != nil {
+ t.Fatal(err)
+ }
+ sched, err := client.Schedules.Update(ctx, "sched", forward.ScheduleUpdateParams{Resources: []forward.ScheduleFileResourceParam{{Type: "file", FileID: "file_test", MountPath: forward.String("/data/test.txt")}}})
+ if err != nil || len(sched.Resources) != 1 || !sched.JSON.Resources.Valid() {
+ t.Fatalf("%+v %v", sched, err)
+ }
+ run, err := client.ScheduleRuns.Get(ctx, "run", forward.ScheduleRunGetParams{IncludeInitialEvents: forward.Bool(true)})
+ if err != nil || len(run.InitialEvents) != 1 || !run.JSON.InitialEvents.Valid() {
+ t.Fatalf("%+v %v", run, err)
+ }
+}
diff --git a/forward/outcomerubric.go b/forward/outcomerubric.go
new file mode 100644
index 0000000..a1636e7
--- /dev/null
+++ b/forward/outcomerubric.go
@@ -0,0 +1,39 @@
+package forward
+
+import (
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apijson"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/respjson"
+)
+
+// OutcomeRubricParam defines acceptance criteria as inline text or an uploaded file.
+// Set Type to "text" with Content, or "file" with FileID.
+type OutcomeRubricParam struct {
+ Type string `json:"type" api:"required"`
+ Content param.Opt[string] `json:"content,omitzero"`
+ FileID param.Opt[string] `json:"file_id,omitzero"`
+ paramObj
+}
+
+func (r OutcomeRubricParam) MarshalJSON() ([]byte, error) {
+ type shadow OutcomeRubricParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *OutcomeRubricParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+// OutcomeRubric contains the text or file reference used to evaluate an Outcome.
+type OutcomeRubric struct {
+ Type string `json:"type"`
+ Content string `json:"content"`
+ FileID string `json:"file_id"`
+ JSON struct {
+ Type respjson.Field
+ Content respjson.Field
+ FileID respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r OutcomeRubric) RawJSON() string { return r.JSON.raw }
+func (r *OutcomeRubric) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
diff --git a/forward/protocol_test.go b/forward/protocol_test.go
index ec6c73d..fd18ab4 100644
--- a/forward/protocol_test.go
+++ b/forward/protocol_test.go
@@ -65,7 +65,7 @@ func TestOptionalNullAndUnionParameters(t *testing.T) {
func TestIdentityOverridesPreserveDynamicKeys(t *testing.T) {
params := forward.IdentityConfigUpsertParams{IdentityConfig: forward.IdentityConfigSpecParam{
- Tools: map[string]forward.ToolOverrideParam{"Read": {Enabled: forward.Bool(false)}},
+ Tools: forward.IdentityToolsUnionParam{OfOverrides: map[string]forward.ToolOverrideParam{"Read": {Enabled: forward.Bool(false)}}},
Skills: map[string]forward.SkillOverrideParam{"skill_one": {Enabled: forward.Bool(false)}, "skill_inherit": param.NullStruct[forward.SkillOverrideParam]()},
MCPServers: map[string]forward.MCPServerOverrideParam{"crm": {Enabled: forward.Bool(true), URL: forward.String("https://crm.test/mcp")}},
GitHubRepositories: map[string]forward.GitHubRepositoryParam{"custom_binding": {AuthorizationToken: forward.String("test_token"), Enabled: param.Null[bool]()}},
diff --git a/forward/schedule.go b/forward/schedule.go
index bba10ae..fc8d3d7 100644
--- a/forward/schedule.go
+++ b/forward/schedule.go
@@ -87,6 +87,7 @@ func (r *ScheduleService) New(ctx context.Context, params ScheduleNewParams, opt
}
type ScheduleNewParams struct {
+ Resources []ScheduleFileResourceParam `json:"resources,omitzero"`
// Forward Identity ID the Schedule belongs to.
IdentityID string `json:"identity_id" api:"required"`
// Forward Template ID to execute.
@@ -176,6 +177,7 @@ func (r *ScheduleService) Update(ctx context.Context, scheduleID string, params
}
type ScheduleUpdateParams struct {
+ Resources []ScheduleFileResourceParam `json:"resources,omitzero"`
// New Schedule name.
Name param.Opt[string] `json:"name,omitzero"`
// New Schedule description.
@@ -321,6 +323,7 @@ func (r *ScheduleArchiveManyResponse) UnmarshalJSON(data []byte) error {
}
type Schedule struct {
+ Resources []ScheduleFileResource `json:"resources"`
// Authoritative creation method of the Schedule: api or tool.
Source string `json:"source"`
SourceSessionID string `json:"source_session_id" api:"nullable"`
@@ -343,6 +346,7 @@ type Schedule struct {
ArchivedAt time.Time `json:"archived_at" format:"date-time"`
PausedReason SchedulePausedReason `json:"paused_reason"`
JSON struct {
+ Resources respjson.Field
Source respjson.Field
SourceSessionID respjson.Field
InitialEventsVersion respjson.Field
@@ -475,3 +479,37 @@ func (r ScheduleInitialEventsItem) RawJSON() string { return r.JSON.raw }
func (r *ScheduleInitialEventsItem) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+
+// ScheduleFileResourceParam attaches a Forward file to each Schedule run.
+type ScheduleFileResourceParam struct {
+ Type string `json:"type" api:"required"`
+ FileID string `json:"file_id" api:"required"`
+ MountPath param.Opt[string] `json:"mount_path,omitzero"`
+ paramObj
+}
+
+func (r ScheduleFileResourceParam) MarshalJSON() ([]byte, error) {
+ type shadow ScheduleFileResourceParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *ScheduleFileResourceParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type ScheduleFileResource struct {
+ Type string `json:"type"`
+ FileID string `json:"file_id"`
+ MountPath string `json:"mount_path"`
+ JSON struct {
+ Type respjson.Field
+ FileID respjson.Field
+ MountPath respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r ScheduleFileResource) RawJSON() string { return r.JSON.raw }
+func (r *ScheduleFileResource) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
diff --git a/forward/schedulerun.go b/forward/schedulerun.go
index 8a2d705..fc565bc 100644
--- a/forward/schedulerun.go
+++ b/forward/schedulerun.go
@@ -88,6 +88,7 @@ func (r *ScheduleRunService) Get(ctx context.Context, runID string, params Sched
}
type ScheduleRunGetParams struct {
+ IncludeInitialEvents param.Opt[bool] `query:"include_initial_events,omitzero" json:"-"`
// Additional ownership constraint.
IdentityID param.Opt[string] `query:"identity_id,omitzero" json:"-"`
paramObj
@@ -98,6 +99,7 @@ func (r ScheduleRunGetParams) URLQuery() (url.Values, error) {
}
type ScheduleRun struct {
+ InitialEvents []SessionEvent `json:"initial_events"`
// Authoritative creation method of the Schedule: api or tool.
Source string `json:"source"`
SourceSessionID string `json:"source_session_id" api:"nullable"`
@@ -144,6 +146,7 @@ type ScheduleRun struct {
// null|Human-readable error message; structured details stay in `error`.
ErrorMessage string `json:"error_message"`
JSON struct {
+ InitialEvents respjson.Field
Source respjson.Field
SourceSessionID respjson.Field
InitialEventsVersion respjson.Field
diff --git a/forward/session.go b/forward/session.go
index e3313db..b8d42fa 100644
--- a/forward/session.go
+++ b/forward/session.go
@@ -92,14 +92,14 @@ func (r SessionListParams) URLQuery() (url.Values, error) {
return apiquery.MarshalWithSettings(r, apiquery.QuerySettings{ArrayFormat: apiquery.ArrayQueryFormatRepeat, NestedFormat: apiquery.NestedQueryFormatBrackets})
}
-// Create Session
+// Create Session. Adds __qca_sdk_ metadata; conflicting reserved values fail before sending.
func (r *SessionService) New(ctx context.Context, params SessionNewParams, opts ...option.RequestOption) (res *Session, err error) {
if params.IdempotencyKey.Valid() {
opts = append([]option.RequestOption{option.WithHeader("Idempotency-Key", fmt.Sprint(params.IdempotencyKey.Value))}, opts...)
}
opts = slices.Concat(r.Options, opts)
path := "sessions"
- err = convention.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
+ err = convention.ExecuteNewSessionRequest(ctx, http.MethodPost, path, params, &res, opts...)
return res, err
}
diff --git a/forward/sessionevent.go b/forward/sessionevent.go
index 1083b09..d754e17 100644
--- a/forward/sessionevent.go
+++ b/forward/sessionevent.go
@@ -157,7 +157,7 @@ type SessionEvent struct {
Result string `json:"result"`
DenyMessage string `json:"deny_message"`
Description string `json:"description"`
- Rubric string `json:"rubric"`
+ Rubric OutcomeRubric `json:"rubric"`
OutcomeID string `json:"outcome_id"`
MaxIterations int64 `json:"max_iterations"`
MessageID string `json:"message_id"`
diff --git a/forward/test_helpers_test.go b/forward/test_helpers_test.go
index fc1b1f4..36c66dd 100644
--- a/forward/test_helpers_test.go
+++ b/forward/test_helpers_test.go
@@ -6,6 +6,7 @@ import (
"errors"
"fmt"
"io"
+ "maps"
"net/http"
"net/url"
"os"
@@ -86,8 +87,8 @@ func operations(t *testing.T) []operationCase {
Cases []operationCase `json:"cases"`
}
readJSON(t, "testdata/api-operation-cases.json", &fixture)
- if fixture.Count != 138 || len(fixture.Cases) != 138 {
- t.Fatal("Forward API scope must contain 138 operations")
+ if fixture.Count != 146 || len(fixture.Cases) != 146 {
+ t.Fatal("Forward API scope must contain 146 operations")
}
return fixture.Cases
}
@@ -265,8 +266,20 @@ func contractClient(t *testing.T, id string, status int) forward.Client {
if err := json.NewDecoder(r.Body).Decode(&actual); err != nil {
t.Error(err)
}
- if !reflect.DeepEqual(actual, bodyValue(c)) {
- t.Errorf("body: %#v want %#v", actual, bodyValue(c))
+ want := maps.Clone(bodyValue(c))
+ if c.OperationID == "createSession" {
+ metadata, _ := want["metadata"].(map[string]any)
+ metadata = maps.Clone(metadata)
+ if metadata == nil {
+ metadata = map[string]any{}
+ }
+ metadata["__qca_sdk_created"] = "true"
+ metadata["__qca_sdk_language"] = "go"
+ metadata["__qca_sdk_version"] = r.Header.Get("X-Qoder-Package-Version")
+ want["metadata"] = metadata
+ }
+ if !reflect.DeepEqual(actual, want) {
+ t.Errorf("body: %#v want %#v", actual, want)
}
} else if c.Body != nil && c.Body.Kind == "multipart" {
if err := r.ParseMultipartForm(1 << 20); err != nil {
diff --git a/forward/testdata/api-contracts.json b/forward/testdata/api-contracts.json
index eb71878..594a5e8 100644
--- a/forward/testdata/api-contracts.json
+++ b/forward/testdata/api-contracts.json
@@ -4047,5 +4047,315 @@
"download": false,
"raw": false,
"empty": false
+ },
+ {
+ "operation_id": "createDream",
+ "service": "DreamService",
+ "entry": "Dreams",
+ "name": "New",
+ "response": {
+ "id": "drm_contract",
+ "type": "dream",
+ "status": "completed",
+ "inputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract",
+ "files_touched": [
+ "MEMORY.md"
+ ]
+ }
+ ],
+ "model": {
+ "id": "auto",
+ "effort": "none",
+ "context_window": 400000
+ },
+ "instructions": "",
+ "usage": {
+ "input_tokens": 5,
+ "output_tokens": 3,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0
+ },
+ "error": null,
+ "created_at": "2026-10-27T00:00:00Z",
+ "ended_at": "2026-10-27T00:01:00Z",
+ "archived_at": null
+ },
+ "stream": false,
+ "download": false,
+ "raw": false,
+ "empty": false
+ },
+ {
+ "operation_id": "listDreams",
+ "service": "DreamService",
+ "entry": "Dreams",
+ "name": "List",
+ "response": {
+ "data": [
+ {
+ "id": "drm_contract",
+ "type": "dream",
+ "status": "completed",
+ "inputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract",
+ "files_touched": [
+ "MEMORY.md"
+ ]
+ }
+ ],
+ "model": {
+ "id": "auto",
+ "effort": "none",
+ "context_window": 400000
+ },
+ "instructions": "",
+ "usage": {
+ "input_tokens": 5,
+ "output_tokens": 3,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0
+ },
+ "error": null,
+ "created_at": "2026-10-27T00:00:00Z",
+ "ended_at": "2026-10-27T00:01:00Z",
+ "archived_at": null
+ }
+ ],
+ "first_id": "drm_contract",
+ "last_id": "drm_contract",
+ "has_more": false
+ },
+ "stream": false,
+ "download": false,
+ "raw": false,
+ "empty": false
+ },
+ {
+ "operation_id": "getDream",
+ "service": "DreamService",
+ "entry": "Dreams",
+ "name": "Get",
+ "response": {
+ "id": "drm_contract",
+ "type": "dream",
+ "status": "completed",
+ "inputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract",
+ "files_touched": [
+ "MEMORY.md"
+ ]
+ }
+ ],
+ "model": {
+ "id": "auto",
+ "effort": "none",
+ "context_window": 400000
+ },
+ "instructions": "",
+ "usage": {
+ "input_tokens": 5,
+ "output_tokens": 3,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0
+ },
+ "error": null,
+ "created_at": "2026-10-27T00:00:00Z",
+ "ended_at": "2026-10-27T00:01:00Z",
+ "archived_at": null
+ },
+ "stream": false,
+ "download": false,
+ "raw": false,
+ "empty": false
+ },
+ {
+ "operation_id": "cancelDream",
+ "service": "DreamService",
+ "entry": "Dreams",
+ "name": "Cancel",
+ "response": {
+ "id": "drm_contract",
+ "type": "dream",
+ "status": "completed",
+ "inputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract",
+ "files_touched": [
+ "MEMORY.md"
+ ]
+ }
+ ],
+ "model": {
+ "id": "auto",
+ "effort": "none",
+ "context_window": 400000
+ },
+ "instructions": "",
+ "usage": {
+ "input_tokens": 5,
+ "output_tokens": 3,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0
+ },
+ "error": null,
+ "created_at": "2026-10-27T00:00:00Z",
+ "ended_at": "2026-10-27T00:01:00Z",
+ "archived_at": null
+ },
+ "stream": false,
+ "download": false,
+ "raw": false,
+ "empty": false
+ },
+ {
+ "operation_id": "archiveDream",
+ "service": "DreamService",
+ "entry": "Dreams",
+ "name": "Archive",
+ "response": {
+ "id": "drm_contract",
+ "type": "dream",
+ "status": "completed",
+ "inputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "memory_store",
+ "memory_store_id": "mem_contract",
+ "files_touched": [
+ "MEMORY.md"
+ ]
+ }
+ ],
+ "model": {
+ "id": "auto",
+ "effort": "none",
+ "context_window": 400000
+ },
+ "instructions": "",
+ "usage": {
+ "input_tokens": 5,
+ "output_tokens": 3,
+ "cache_creation_input_tokens": 0,
+ "cache_read_input_tokens": 0
+ },
+ "error": null,
+ "created_at": "2026-10-27T00:00:00Z",
+ "ended_at": "2026-10-27T00:01:00Z",
+ "archived_at": null
+ },
+ "stream": false,
+ "download": false,
+ "raw": false,
+ "empty": false
+ },
+ {
+ "operation_id": "listChannelPairings",
+ "service": "ChannelPairingService",
+ "entry": "ChannelPairings",
+ "name": "List",
+ "response": {
+ "data": [
+ {
+ "id": "cp_contract",
+ "channel_id": "ch_contract",
+ "identity_id": "idn_contract",
+ "template_id": "tmpl_contract",
+ "scope_type": "direct",
+ "scope_external_id": "user_contract",
+ "scope_display_name": "Contract user",
+ "status": "active",
+ "paired_at": "2026-10-27T00:00:00Z",
+ "created_at": "2026-10-27T00:00:00Z"
+ }
+ ],
+ "first_id": "cp_contract",
+ "last_id": "cp_contract",
+ "has_more": false
+ },
+ "stream": false,
+ "download": false,
+ "raw": false,
+ "empty": false
+ },
+ {
+ "operation_id": "getChannelPairing",
+ "service": "ChannelPairingService",
+ "entry": "ChannelPairings",
+ "name": "Get",
+ "response": {
+ "id": "cp_contract",
+ "channel_id": "ch_contract",
+ "identity_id": "idn_contract",
+ "template_id": "tmpl_contract",
+ "scope_type": "direct",
+ "scope_external_id": "user_contract",
+ "scope_display_name": "Contract user",
+ "status": "active",
+ "paired_at": "2026-10-27T00:00:00Z",
+ "created_at": "2026-10-27T00:00:00Z"
+ },
+ "stream": false,
+ "download": false,
+ "raw": false,
+ "empty": false
+ },
+ {
+ "operation_id": "updateChannelPairing",
+ "service": "ChannelPairingService",
+ "entry": "ChannelPairings",
+ "name": "Update",
+ "response": {
+ "id": "cp_contract",
+ "channel_id": "ch_contract",
+ "identity_id": "idn_contract",
+ "template_id": "tmpl_contract",
+ "scope_type": "direct",
+ "scope_external_id": "user_contract",
+ "scope_display_name": "Contract user",
+ "status": "active",
+ "paired_at": "2026-10-27T00:00:00Z",
+ "created_at": "2026-10-27T00:00:00Z"
+ },
+ "stream": false,
+ "download": false,
+ "raw": false,
+ "empty": false
}
]
diff --git a/forward/testdata/api-operation-cases.json b/forward/testdata/api-operation-cases.json
index 99eb27f..23edb39 100644
--- a/forward/testdata/api-operation-cases.json
+++ b/forward/testdata/api-operation-cases.json
@@ -1,6 +1,6 @@
{
"schema_version": 1,
- "operation_count": 138,
+ "operation_count": 146,
"cases": [
{
"operation_id": "addSessionResource",
@@ -5752,6 +5752,282 @@
"page": "start +/=?"
}
}
+ },
+ {
+ "operation_id": "createDream",
+ "resource": "Dreams",
+ "clients": {
+ "python": "dreams",
+ "typescript": "dreams",
+ "go": "Dreams"
+ },
+ "methods": {
+ "python": "create",
+ "typescript": "create",
+ "go": "New"
+ },
+ "http_method": "POST",
+ "path": "/dreams",
+ "parameters": [],
+ "request_body": {
+ "kind": "json",
+ "value": {
+ "inputs": [
+ {
+ "type": "identity_template",
+ "identity_id": "idn_contract",
+ "template_id": "tmpl_contract"
+ },
+ {
+ "type": "sessions",
+ "session_ids": [
+ "sess_contract"
+ ]
+ }
+ ],
+ "model": {
+ "id": "auto",
+ "effort": "none",
+ "context_window": 400000
+ },
+ "instructions": "Keep facts"
+ }
+ }
+ },
+ {
+ "operation_id": "listDreams",
+ "resource": "Dreams",
+ "clients": {
+ "python": "dreams",
+ "typescript": "dreams",
+ "go": "Dreams"
+ },
+ "methods": {
+ "python": "list",
+ "typescript": "list",
+ "go": "List"
+ },
+ "http_method": "GET",
+ "path": "/dreams",
+ "parameters": [
+ {
+ "wire_name": "limit",
+ "location": "query",
+ "required": false,
+ "value": 1
+ },
+ {
+ "wire_name": "after_id",
+ "location": "query",
+ "required": false,
+ "value": "drm_before"
+ },
+ {
+ "wire_name": "include_archived",
+ "location": "query",
+ "required": false,
+ "value": true
+ }
+ ]
+ },
+ {
+ "operation_id": "getDream",
+ "resource": "Dreams",
+ "clients": {
+ "python": "dreams",
+ "typescript": "dreams",
+ "go": "Dreams"
+ },
+ "methods": {
+ "python": "retrieve",
+ "typescript": "retrieve",
+ "go": "Get"
+ },
+ "http_method": "GET",
+ "path": "/dreams/{dream_id}",
+ "parameters": [
+ {
+ "wire_name": "dream_id",
+ "location": "path",
+ "required": true,
+ "value": "contract"
+ }
+ ]
+ },
+ {
+ "operation_id": "cancelDream",
+ "resource": "Dreams",
+ "clients": {
+ "python": "dreams",
+ "typescript": "dreams",
+ "go": "Dreams"
+ },
+ "methods": {
+ "python": "cancel",
+ "typescript": "cancel",
+ "go": "Cancel"
+ },
+ "http_method": "POST",
+ "path": "/dreams/{dream_id}/cancel",
+ "parameters": [
+ {
+ "wire_name": "dream_id",
+ "location": "path",
+ "required": true,
+ "value": "contract"
+ }
+ ]
+ },
+ {
+ "operation_id": "archiveDream",
+ "resource": "Dreams",
+ "clients": {
+ "python": "dreams",
+ "typescript": "dreams",
+ "go": "Dreams"
+ },
+ "methods": {
+ "python": "archive",
+ "typescript": "archive",
+ "go": "Archive"
+ },
+ "http_method": "POST",
+ "path": "/dreams/{dream_id}/archive",
+ "parameters": [
+ {
+ "wire_name": "dream_id",
+ "location": "path",
+ "required": true,
+ "value": "contract"
+ }
+ ]
+ },
+ {
+ "operation_id": "listChannelPairings",
+ "resource": "ChannelPairings",
+ "clients": {
+ "python": "channel_pairings",
+ "typescript": "channelPairings",
+ "go": "ChannelPairings"
+ },
+ "methods": {
+ "python": "list",
+ "typescript": "list",
+ "go": "List"
+ },
+ "http_method": "GET",
+ "path": "/channel_pairings",
+ "parameters": [
+ {
+ "wire_name": "channel_id",
+ "location": "query",
+ "required": false,
+ "value": "ch_contract"
+ },
+ {
+ "wire_name": "status",
+ "location": "query",
+ "required": false,
+ "value": "active"
+ },
+ {
+ "wire_name": "target_type",
+ "location": "query",
+ "required": false,
+ "value": "user"
+ },
+ {
+ "wire_name": "target_external_id",
+ "location": "query",
+ "required": false,
+ "value": "user_contract"
+ },
+ {
+ "wire_name": "identity_id",
+ "location": "query",
+ "required": false,
+ "value": "idn_contract"
+ },
+ {
+ "wire_name": "template_id",
+ "location": "query",
+ "required": false,
+ "value": "tmpl_contract"
+ },
+ {
+ "wire_name": "limit",
+ "location": "query",
+ "required": false,
+ "value": 1
+ },
+ {
+ "wire_name": "after_id",
+ "location": "query",
+ "required": false,
+ "value": "cp_before"
+ }
+ ]
+ },
+ {
+ "operation_id": "getChannelPairing",
+ "resource": "ChannelPairings",
+ "clients": {
+ "python": "channel_pairings",
+ "typescript": "channelPairings",
+ "go": "ChannelPairings"
+ },
+ "methods": {
+ "python": "retrieve",
+ "typescript": "retrieve",
+ "go": "Get"
+ },
+ "http_method": "GET",
+ "path": "/channel_pairings/{pairing_id}",
+ "parameters": [
+ {
+ "wire_name": "pairing_id",
+ "location": "path",
+ "required": true,
+ "value": "contract"
+ }
+ ]
+ },
+ {
+ "operation_id": "updateChannelPairing",
+ "resource": "ChannelPairings",
+ "clients": {
+ "python": "channel_pairings",
+ "typescript": "channelPairings",
+ "go": "ChannelPairings"
+ },
+ "methods": {
+ "python": "update",
+ "typescript": "update",
+ "go": "Update"
+ },
+ "http_method": "POST",
+ "path": "/channel_pairings/{pairing_id}",
+ "parameters": [
+ {
+ "wire_name": "pairing_id",
+ "location": "path",
+ "required": true,
+ "value": "contract"
+ }
+ ],
+ "request_body": {
+ "kind": "json",
+ "value": {
+ "identity_id": "idn_contract",
+ "template_id": "tmpl_contract"
+ }
+ }
+ }
+ ],
+ "extensions": [
+ {
+ "source": "https://docs.qoder.com/cloud-agents/api/forward/dreams/create; https://docs.qoder.com/cloud-agents/api/forward/channels/list-channel-pairings; https://docs.qoder.com/cloud-agents/api/vaults/start-oauth (2026-10-27)",
+ "operations": 8
}
]
}
diff --git a/managed/agent.go b/managed/agent.go
index 00cae55..c4dfa33 100644
--- a/managed/agent.go
+++ b/managed/agent.go
@@ -2852,35 +2852,19 @@ type ManagedAgentsModel = string
// Model identifier and configuration.
type ManagedAgentsModelConfig struct {
- ContextWindow int64 `json:"context_window"`
-
- // The model that will power your agent.
- //
- // See [models](https://docs.qoder.com/cloud-agents/api/models/list) for additional
- // details and options.
- ID ManagedAgentsModel `json:"id" api:"required"`
- // How hard the model works on each turn. Sets `output_config.effort` on every
- // Messages call the session makes.
- Effort ManagedAgentsModelConfigEffortUnion `json:"effort"`
- // Geographic region for model inference. When unset, requests fall through to the
- // workspace's default_inference_geo.
- InferenceGeo string `json:"inference_geo"`
- // Inference speed mode. `fast` provides significantly faster output token
- // generation at premium pricing. Not all models support `fast`; invalid
- // combinations are rejected at create time.
- //
- // Any of "standard", "fast".
- Speed ManagedAgentsModelConfigSpeed `json:"speed"`
- // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
- JSON struct {
- ContextWindow respjson.Field
-
- ID respjson.Field
- Effort respjson.Field
- InferenceGeo respjson.Field
- Speed respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
+ InferenceGeo string `json:"inference_geo"`
+ ID string `json:"id" api:"required"`
+ Effort string `json:"effort"`
+ ContextWindow int64 `json:"context_window"`
+ EffectiveContextWindow int64 `json:"effective_context_window"`
+ JSON struct {
+ InferenceGeo respjson.Field
+ ID respjson.Field
+ Effort respjson.Field
+ ContextWindow respjson.Field
+ EffectiveContextWindow respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
} `json:"-"`
}
@@ -2994,34 +2978,14 @@ const (
//
// The property ID is required.
type ManagedAgentsModelConfigParams struct {
- ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
-
- // The model that will power your agent.
- //
- // See [models](https://docs.qoder.com/cloud-agents/api/models/list) for additional
- // details and options.
- ID ManagedAgentsModel `json:"id,omitzero" api:"required"`
- // Geographic region for model inference. When unset, requests fall through to the
- // workspace's default_inference_geo. On update, `model` is whole-object
- // replacement — omitting inference_geo clears it.
- InferenceGeo param.Opt[string] `json:"inference_geo,omitzero"`
- // How hard the model works on each inference call. Accepts a bare level string
- // (`"high"`) or `{"type": "high"}`. On create, omitting it resolves the per-model
- // default; on update, omitting it leaves the stored value unchanged.
- Effort ManagedAgentsModelConfigParamsEffortUnion `json:"effort,omitzero"`
- // Inference speed mode. `fast` provides significantly faster output token
- // generation at premium pricing. Not all models support `fast`; invalid
- // combinations are rejected at create time.
- //
- // Any of "standard", "fast".
- Speed ManagedAgentsModelConfigParamsSpeed `json:"speed,omitzero"`
+ InferenceGeo param.Opt[string] `json:"inference_geo,omitzero"`
+ ID string `json:"id" api:"required"`
+ Effort param.Opt[string] `json:"effort,omitzero"`
+ ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
paramObj
}
func (r ManagedAgentsModelConfigParams) MarshalJSON() (data []byte, err error) {
- if r.Speed != "" {
- return nil, fmt.Errorf("Qoder does not support model.speed")
- }
type shadow ManagedAgentsModelConfigParams
return param.MarshalObject(r, (*shadow)(&r))
}
diff --git a/managed/agent_test.go b/managed/agent_test.go
index 37b3c08..62acb25 100644
--- a/managed/agent_test.go
+++ b/managed/agent_test.go
@@ -91,14 +91,13 @@ func TestRequestFieldSemantics(t *testing.T) {
if _, ok := m["authorization_token"]; ok {
t.Fatal("empty legacy authorization_token sent")
}
- model := managed.ManagedAgentsModelConfigParams{ID: "qoder-model", ContextWindow: managed.Int(128000), Effort: managed.ManagedAgentsModelConfigParamsEffortUnion{OfManagedAgentsModelConfigsEffortManagedAgentsEffortLevel: managed.String("high")}}
+ model := managed.ManagedAgentsModelConfigParams{ID: "qoder-model", ContextWindow: managed.Int(128000), Effort: managed.String("high")}
m = jsonObject(t, model)
if m["effort"] != "high" || m["context_window"] != float64(128000) {
t.Fatal(m)
}
- model.Speed = "fast"
- if _, err := json.Marshal(model); err == nil {
- t.Fatal("unsupported model.speed should be rejected")
+ if _, ok := m["speed"]; ok {
+ t.Fatal("unsupported model.speed was sent")
}
}
@@ -115,7 +114,7 @@ func TestQoderResponseFields(t *testing.T) {
t.Fatal("raw/unknown JSON lost")
}
}
- if a.Model.Effort.Type != "high" || a.Model.Effort.AsHigh().Type != "high" || a.Model.ContextWindow != 128000 {
+ if a.Model.Effort != "high" || a.Model.ContextWindow != 128000 {
t.Fatalf("model fields: %+v", a.Model)
}
var skill managed.Skill
diff --git a/managed/bucketstorage.go b/managed/bucketstorage.go
new file mode 100644
index 0000000..9096e46
--- /dev/null
+++ b/managed/bucketstorage.go
@@ -0,0 +1,109 @@
+package managed
+
+import (
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apijson"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/respjson"
+)
+
+// BucketStorageParam declares up to eight OSS bucket mounts in a cloud Environment.
+type BucketStorageParam struct {
+ Buckets []OSSBucketParam `json:"buckets" api:"required"`
+ paramObj
+}
+
+func (r BucketStorageParam) MarshalJSON() ([]byte, error) {
+ type shadow BucketStorageParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *BucketStorageParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+// OSSBucketParam requires credentials for new buckets. Omit Credential on update to retain it.
+type OSSBucketParam struct {
+ Name string `json:"name" api:"required"`
+ Provider string `json:"provider" api:"required"`
+ Region string `json:"region" api:"required"`
+ Bucket string `json:"bucket" api:"required"`
+ Prefix param.Opt[string] `json:"prefix,omitzero"`
+ Access param.Opt[string] `json:"access,omitzero"`
+ AcceleratorEndpoint param.Opt[string] `json:"accelerator_endpoint,omitzero"`
+ Credential OSSBucketCredentialParam `json:"credential,omitzero"`
+ paramObj
+}
+
+func (r OSSBucketParam) MarshalJSON() ([]byte, error) {
+ type shadow OSSBucketParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *OSSBucketParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+// OSSBucketCredentialParam accepts ram_role with RoleArn, or access_key with ID and secret.
+// A read-view credential without secrets may be echoed to retain it on update.
+type OSSBucketCredentialParam struct {
+ Type string `json:"type" api:"required"`
+ RoleArn param.Opt[string] `json:"role_arn,omitzero"`
+ AccessKeyID param.Opt[string] `json:"access_key_id,omitzero"`
+ AccessKeySecret param.Opt[string] `json:"access_key_secret,omitzero"`
+ paramObj
+}
+
+func (r OSSBucketCredentialParam) MarshalJSON() ([]byte, error) {
+ type shadow OSSBucketCredentialParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *OSSBucketCredentialParam) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type BucketStorage struct {
+ Buckets []OSSBucket `json:"buckets"`
+ JSON struct {
+ Buckets respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r BucketStorage) RawJSON() string { return r.JSON.raw }
+func (r *BucketStorage) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type OSSBucket struct {
+ Name string `json:"name"`
+ Provider string `json:"provider"`
+ Region string `json:"region"`
+ Bucket string `json:"bucket"`
+ Prefix string `json:"prefix"`
+ Access string `json:"access"`
+ AcceleratorEndpoint string `json:"accelerator_endpoint"`
+ Credential OSSBucketCredential `json:"credential"`
+ JSON struct {
+ Name respjson.Field
+ Provider respjson.Field
+ Region respjson.Field
+ Bucket respjson.Field
+ Prefix respjson.Field
+ Access respjson.Field
+ AcceleratorEndpoint respjson.Field
+ Credential respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r OSSBucket) RawJSON() string { return r.JSON.raw }
+func (r *OSSBucket) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+// OSSBucketCredential is the API read view. It contains no role ARN or secret.
+type OSSBucketCredential struct {
+ Type string `json:"type"`
+ AccessKeyID string `json:"access_key_id"`
+ JSON struct {
+ Type respjson.Field
+ AccessKeyID respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r OSSBucketCredential) RawJSON() string { return r.JSON.raw }
+func (r *OSSBucketCredential) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
diff --git a/managed/client.go b/managed/client.go
index 1b9db20..991010a 100644
--- a/managed/client.go
+++ b/managed/client.go
@@ -15,6 +15,7 @@ const DefaultBaseURL = "https://api.qoder.com/api/v1/cloud/"
// Client exposes concrete services; nested services follow the upstream hierarchy.
// A client can be shared between goroutines. Configure options before first use.
type Client struct {
+ OAuth OAuthService
Options []option.RequestOption
Agents AgentService
Sessions SessionService
@@ -40,7 +41,8 @@ func NewClient(opts ...option.RequestOption) Client {
}
defaults = append(defaults, convention.EnvironmentAuthentication())
opts = slices.Concat(defaults, opts)
- return Client{Options: opts, Agents: NewAgentService(opts...), Sessions: NewSessionService(opts...), Deployments: NewDeploymentService(opts...), DeploymentRuns: NewDeploymentRunService(opts...), Dreams: NewDreamService(opts...), Environments: NewEnvironmentService(opts...), Skills: NewSkillService(opts...), Vaults: NewVaultService(opts...), Files: NewFileService(opts...), MemoryStores: NewMemoryStoreService(opts...), Models: NewModelService(opts...)}
+ return Client{Options: opts, Agents: NewAgentService(opts...), Sessions: NewSessionService(opts...), Deployments: NewDeploymentService(opts...), DeploymentRuns: NewDeploymentRunService(opts...), OAuth: NewOAuthService(opts...),
+ Dreams: NewDreamService(opts...), Environments: NewEnvironmentService(opts...), Skills: NewSkillService(opts...), Vaults: NewVaultService(opts...), Files: NewFileService(opts...), MemoryStores: NewMemoryStoreService(opts...), Models: NewModelService(opts...)}
}
func String(v string) param.Opt[string] { return param.NewOpt(v) }
diff --git a/managed/client_test.go b/managed/client_test.go
index 80cda84..9bb1051 100644
--- a/managed/client_test.go
+++ b/managed/client_test.go
@@ -14,7 +14,7 @@ import (
func TestManagedAPIInventory(t *testing.T) {
fixtures := contracts(t)
- if len(fixtures) != 106 {
+ if len(fixtures) != 107 {
t.Fatalf("got %d API contracts", len(fixtures))
}
expected := map[string]bool{}
diff --git a/managed/dream.go b/managed/dream.go
index b154b98..2d85748 100644
--- a/managed/dream.go
+++ b/managed/dream.go
@@ -418,55 +418,30 @@ func (r *DreamMemoryStoreInputParam) UnmarshalJSON(data []byte) error {
// Model identifier and configuration applied to every pipeline stage. Same wire
// shape as the Agents API ModelConfig.
type DreamModelConfig struct {
- // Model identifier. 1-256 characters.
- ID string `json:"id" api:"required"`
- // Inference speed mode. `fast` provides significantly faster output token
- // generation at premium pricing. Not all models support `fast`; invalid
- // combinations are rejected at create time.
- //
- // Any of "standard", "fast".
- Speed DreamModelConfigSpeed `json:"speed"`
- // JSON contains metadata for fields, check presence with [respjson.Field.Valid].
- JSON struct {
- ID respjson.Field
- Speed respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
+ ID string `json:"id"`
+ Effort string `json:"effort"`
+ ContextWindow int64 `json:"context_window"`
+ JSON struct {
+ ID respjson.Field
+ Effort respjson.Field
+ ContextWindow respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
} `json:"-"`
}
-// Returns the unmodified JSON received from the API
-func (r DreamModelConfig) RawJSON() string { return r.JSON.raw }
-func (r *DreamModelConfig) UnmarshalJSON(data []byte) error {
- return apijson.UnmarshalRoot(data, r)
-}
+func (r DreamModelConfig) RawJSON() string { return r.JSON.raw }
+func (r *DreamModelConfig) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
-// Inference speed mode. `fast` provides significantly faster output token
-// generation at premium pricing. Not all models support `fast`; invalid
-// combinations are rejected at create time.
-type DreamModelConfigSpeed string
-
-const (
- DreamModelConfigSpeedStandard DreamModelConfigSpeed = "standard"
- DreamModelConfigSpeedFast DreamModelConfigSpeed = "fast"
-)
-
-// Model identifier and configuration applied to every pipeline stage.
-//
-// The property ID is required.
+// DreamModelConfigParam selects an available model and optional reasoning settings.
type DreamModelConfigParam struct {
- // Model identifier. 1-256 characters.
- ID string `json:"id" api:"required"`
- // Inference speed mode. `fast` provides significantly faster output token
- // generation at premium pricing. Not all models support `fast`; invalid
- // combinations are rejected at create time.
- //
- // Any of "standard", "fast".
- Speed DreamModelConfigParamSpeed `json:"speed,omitzero"`
+ ID string `json:"id" api:"required"`
+ Effort param.Opt[string] `json:"effort,omitzero"`
+ ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
paramObj
}
-func (r DreamModelConfigParam) MarshalJSON() (data []byte, err error) {
+func (r DreamModelConfigParam) MarshalJSON() ([]byte, error) {
type shadow DreamModelConfigParam
return param.MarshalObject(r, (*shadow)(&r))
}
@@ -474,16 +449,6 @@ func (r *DreamModelConfigParam) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
-// Inference speed mode. `fast` provides significantly faster output token
-// generation at premium pricing. Not all models support `fast`; invalid
-// combinations are rejected at create time.
-type DreamModelConfigParamSpeed string
-
-const (
- DreamModelConfigParamSpeedStandard DreamModelConfigParamSpeed = "standard"
- DreamModelConfigParamSpeedFast DreamModelConfigParamSpeed = "fast"
-)
-
// An output memory store the dream writes consolidated memories into.
type DreamOutput struct {
// Paths of memory files created, modified or deleted.
@@ -855,7 +820,7 @@ func (r *OutputBehaviorUpdateExistingParam) UnmarshalJSON(data []byte) error {
type DreamNewParams struct {
Inputs []DreamInputUnionParam `json:"inputs,omitzero" api:"required"`
// Model identifier and configuration applied to every pipeline stage.
- Model DreamNewParamsModelUnion `json:"model,omitzero" api:"required"`
+ Model DreamNewParamsModelUnion `json:"model,omitzero"`
Instructions param.Opt[string] `json:"instructions,omitzero"`
// The default destination: the job creates a new output memory store as a clone of
// the memory_store input and writes the consolidated memories into it. The input
diff --git a/managed/environment.go b/managed/environment.go
index e5549e1..be27f34 100644
--- a/managed/environment.go
+++ b/managed/environment.go
@@ -147,7 +147,9 @@ func (r *EnvironmentService) Archive(ctx context.Context, environmentID string,
// `cloud` environment configuration.
type CloudConfig struct {
- SetupScript string `json:"setup_script"`
+ // Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
+ Storage BucketStorage `json:"storage"`
+ SetupScript string `json:"setup_script"`
// Network configuration policy.
Networking CloudConfigNetworkingUnion `json:"networking" api:"required"`
// Package manager configuration.
@@ -156,6 +158,7 @@ type CloudConfig struct {
Type constant.Cloud `json:"type" default:"cloud"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
+ Storage respjson.Field
SetupScript respjson.Field
Networking respjson.Field
Packages respjson.Field
@@ -246,7 +249,9 @@ func (r *CloudConfigNetworkingUnion) UnmarshalJSON(data []byte) error {
//
// The property Type is required.
type CloudConfigParams struct {
- SetupScript param.Opt[string] `json:"setup_script,omitzero"`
+ // Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
+ Storage BucketStorageParam `json:"storage,omitzero"`
+ SetupScript param.Opt[string] `json:"setup_script,omitzero"`
// Network configuration policy. Omit on update to preserve the existing value.
Networking CloudConfigParamsNetworkingUnion `json:"networking,omitzero"`
// Specify packages (and optionally their versions) available in this environment.
@@ -395,7 +400,9 @@ func (r *Environment) UnmarshalJSON(data []byte) error {
//
// Use the methods beginning with 'As' to cast the union to one of its variants.
type EnvironmentConfigUnion struct {
- SetupScript string `json:"setup_script"`
+ // Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
+ Storage BucketStorage `json:"storage"`
+ SetupScript string `json:"setup_script"`
// This field is from variant [CloudConfig].
Networking CloudConfigNetworkingUnion `json:"networking"`
// This field is from variant [CloudConfig].
@@ -403,6 +410,7 @@ type EnvironmentConfigUnion struct {
// Any of "cloud", "self_hosted".
Type string `json:"type"`
JSON struct {
+ Storage respjson.Field
SetupScript respjson.Field
Networking respjson.Field
Packages respjson.Field
diff --git a/managed/memorystore.go b/managed/memorystore.go
index e3f9575..680a4e4 100644
--- a/managed/memorystore.go
+++ b/managed/memorystore.go
@@ -292,7 +292,9 @@ func (r *MemoryStoreUpdateParams) UnmarshalJSON(data []byte) error {
}
type MemoryStoreListParams struct {
- Name param.Opt[string] `query:"name,omitzero" json:"-"`
+ AfterID param.Opt[string] `query:"after_id,omitzero" json:"-"`
+ BeforeID param.Opt[string] `query:"before_id,omitzero" json:"-"`
+ Name param.Opt[string] `query:"name,omitzero" json:"-"`
// Return only stores whose `created_at` is at or after this time (inclusive). Sent
// on the wire as `created_at[gte]`.
diff --git a/managed/oauth.go b/managed/oauth.go
new file mode 100644
index 0000000..b0d5e40
--- /dev/null
+++ b/managed/oauth.go
@@ -0,0 +1,60 @@
+package managed
+
+import (
+ "context"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/apijson"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/option"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/respjson"
+ "net/http"
+ "slices"
+)
+
+type OAuthService struct{ Options []option.RequestOption }
+
+func NewOAuthService(opts ...option.RequestOption) OAuthService {
+ return OAuthService{Options: slices.Clone(opts)}
+}
+
+// Start returns an authorization URL; the user completes authorization in their browser.
+func (r *OAuthService) Start(ctx context.Context, params OAuthStartParams, opts ...option.RequestOption) (res *OAuthStartResponse, err error) {
+ if params.WorkspaceID.Valid() {
+ opts = append([]option.RequestOption{option.WithHeader("qoder-workspace-id", params.WorkspaceID.Value)}, opts...)
+ }
+ opts = slices.Concat(r.Options, opts)
+ err = convention.ExecuteNewRequest(ctx, http.MethodPost, "oauth/start", params, &res, opts...)
+ return res, err
+}
+
+type OAuthStartParams struct {
+ WorkspaceID param.Opt[string] `header:"qoder-workspace-id,omitzero" json:"-"`
+
+ VaultID string `json:"vault_id"`
+ MCPServerURL string `json:"mcp_server_url"`
+ ClientID param.Opt[string] `json:"client_id,omitzero"`
+ ClientSecret param.Opt[string] `json:"client_secret,omitzero"`
+ paramObj
+}
+
+func (r OAuthStartParams) MarshalJSON() ([]byte, error) {
+ type shadow OAuthStartParams
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *OAuthStartParams) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+type OAuthStartResponse struct {
+ AuthorizationURL string `json:"authorization_url"`
+ State string `json:"state"`
+ CallbackOrigin string `json:"callback_origin"`
+ JSON struct {
+ AuthorizationURL respjson.Field
+ State respjson.Field
+ CallbackOrigin respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r OAuthStartResponse) RawJSON() string { return r.JSON.raw }
+func (r *OAuthStartResponse) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
diff --git a/managed/official_contract_test.go b/managed/official_contract_test.go
new file mode 100644
index 0000000..94e302e
--- /dev/null
+++ b/managed/official_contract_test.go
@@ -0,0 +1,111 @@
+package managed_test
+
+import (
+ "context"
+ "encoding/json"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/option"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/managed"
+ "io"
+ "net/http"
+ "reflect"
+ "testing"
+)
+
+func TestOfficialDreamModelContract(t *testing.T) {
+ body := jsonObject(t, managed.DreamNewParams{Inputs: []managed.DreamInputUnionParam{}})
+ if _, ok := body["model"]; ok {
+ t.Fatal("default model should be omitted", body)
+ }
+ cfg := managed.DreamModelConfigParam{ID: "auto", Effort: managed.String("none"), ContextWindow: managed.Int(400000)}
+ body = jsonObject(t, cfg)
+ if body["effort"] != "none" || body["context_window"] != float64(400000) {
+ t.Fatal(body)
+ }
+ for _, raw := range []string{`{"model":{"id":"auto","effort":"none","context_window":400000}}`} {
+ var dream managed.Dream
+ if err := json.Unmarshal([]byte(raw), &dream); err != nil {
+ t.Fatal(err)
+ }
+ if dream.Model.ID != "auto" || dream.Model.Effort != "none" || dream.Model.ContextWindow != 400000 {
+ t.Fatalf("lost model: %+v", dream.Model)
+ }
+ }
+}
+
+func TestOfficialOAuthAPIContract(t *testing.T) {
+ c := contractClient(t, "OAuthService", "Start")
+ result, err := c.OAuth.Start(context.Background(), managed.OAuthStartParams{VaultID: "vault", MCPServerURL: "https://mcp.example.com"})
+ if err != nil {
+ t.Fatal(err)
+ }
+ checkFields(t, reflect.ValueOf(*result), "oauth")
+}
+func TestOfficialOAuthSecretAndMemoryCursors(t *testing.T) {
+ calls := 0
+ c := managed.NewClient(option.WithPAT("test"), option.WithBaseURL("https://qoder.test/api/v1/cloud"), option.WithMaxRetries(0), option.WithHTTPClient(&http.Client{Transport: roundTripFunc(func(r *http.Request) (*http.Response, error) {
+ calls++
+ if calls == 1 {
+ if r.URL.Path != "/api/v1/cloud/oauth/start" || r.Method != "POST" || r.URL.RawQuery != "" || r.Header.Get("qoder-workspace-id") != "workspace" {
+ t.Fatal(r.URL)
+ }
+ b, _ := io.ReadAll(r.Body)
+ var body map[string]any
+ _ = json.Unmarshal(b, &body)
+ if !reflect.DeepEqual(body, map[string]any{"vault_id": "vault", "mcp_server_url": "https://mcp.example.com", "client_id": "client", "client_secret": "test-secret"}) {
+ t.Fatal(body)
+ }
+ return reply(r, 200, `{"authorization_url":"https://auth.example.com","state":"opaque","callback_origin":"https://api.example.com"}`), nil
+ }
+ if r.URL.Path != "/api/v1/cloud/memory_stores" || r.URL.Query().Get("before_id") != "mem_before" || r.URL.Query().Get("include_archived") != "false" {
+ t.Fatal(r.URL)
+ }
+ return reply(r, 200, `{"data":[],"has_more":false}`), nil
+ })}))
+ result, err := c.OAuth.Start(context.Background(), managed.OAuthStartParams{VaultID: "vault", MCPServerURL: "https://mcp.example.com", ClientID: managed.String("client"), ClientSecret: managed.String("test-secret"), WorkspaceID: managed.String("workspace")})
+ if err != nil || result.State != "opaque" || !result.JSON.AuthorizationURL.Valid() {
+ t.Fatalf("%+v %v", result, err)
+ }
+ if _, err = c.MemoryStores.List(context.Background(), managed.MemoryStoreListParams{BeforeID: managed.String("mem_before"), IncludeArchived: managed.Bool(false)}); err != nil {
+ t.Fatal(err)
+ }
+ if calls != 2 {
+ t.Fatal(calls)
+ }
+}
+func TestOfficialOSSStorageWriteReadAndClear(t *testing.T) {
+ for _, bucket := range []managed.OSSBucketParam{
+ {Name: "assets", Provider: "aliyun-oss", Region: "cn-hangzhou", Bucket: "example", Credential: managed.OSSBucketCredentialParam{Type: "ram_role", RoleArn: managed.String("test-role")}},
+ {Name: "assets", Provider: "aliyun-oss", Region: "cn-hangzhou", Bucket: "example", Credential: managed.OSSBucketCredentialParam{Type: "access_key", AccessKeyID: managed.String("test-ak"), AccessKeySecret: managed.String("test-secret")}},
+ {Name: "assets", Provider: "aliyun-oss", Region: "cn-hangzhou", Bucket: "example"},
+ } {
+ body := jsonObject(t, managed.CloudConfigParams{Storage: managed.BucketStorageParam{Buckets: []managed.OSSBucketParam{bucket}}})
+ stored := body["storage"].(map[string]any)["buckets"].([]any)[0].(map[string]any)
+ if bucket.Credential.Type == "" {
+ if _, ok := stored["credential"]; ok {
+ t.Fatal("must preserve stored credentials by omission", stored)
+ }
+ } else {
+ cred := stored["credential"].(map[string]any)
+ if cred["type"] != bucket.Credential.Type {
+ t.Fatal(cred)
+ }
+ if bucket.Credential.Type == "access_key" && cred["access_key_secret"] != "test-secret" {
+ t.Fatal(cred)
+ }
+ }
+ }
+ body := jsonObject(t, managed.CloudConfigParams{Storage: managed.BucketStorageParam{Buckets: []managed.OSSBucketParam{}}})
+ if len(body["storage"].(map[string]any)["buckets"].([]any)) != 0 {
+ t.Fatal(body)
+ }
+ var env managed.Environment
+ if err := json.Unmarshal([]byte(`{"config":{"type":"cloud","storage":{"buckets":[{"name":"assets","provider":"aliyun-oss","region":"cn-hangzhou","bucket":"example","credential":{"type":"access_key","access_key_id":"test****"}}]}}}`), &env); err != nil {
+ t.Fatal(err)
+ }
+ if !env.Config.JSON.Storage.Valid() || env.Config.Storage.Buckets[0].Credential.AccessKeyID != "test****" {
+ t.Fatalf("%+v", env.Config)
+ }
+ if _, ok := reflect.TypeOf(managed.OSSBucketCredential{}).FieldByName("AccessKeySecret"); ok {
+ t.Fatal("read view must not expose secret")
+ }
+}
diff --git a/managed/qoder_types_test.go b/managed/qoder_types_test.go
index 1bc9df1..515ac8d 100644
--- a/managed/qoder_types_test.go
+++ b/managed/qoder_types_test.go
@@ -72,6 +72,11 @@ func TestQoderFieldAlignment(t *testing.T) {
if (name == "ManagedAgentsBudgetLimit" || name == "ManagedAgentsBudgetLimitParam") && f == "MaxListCost" {
f = "MaxCreditCost"
}
+ // QCA rejects speed for Agent/Dream model configuration.
+ // https://docs.qoder.com/cloud-agents/api/dreams/create#model-object
+ if f == "Speed" && (name == "ManagedAgentsModelConfig" || name == "ManagedAgentsModelConfigParams" || name == "DreamModelConfig" || name == "DreamModelConfigParam") {
+ f = "Effort"
+ }
if !actual[name][f] {
t.Errorf("upstream field missing: %s.%s", name, f)
}
diff --git a/managed/request_contracts_test.go b/managed/request_contracts_test.go
index 3d35500..0b4a646 100644
--- a/managed/request_contracts_test.go
+++ b/managed/request_contracts_test.go
@@ -52,6 +52,17 @@ func TestManagedDocumentedRequestBodies(t *testing.T) {
if err = json.Unmarshal(actual, &got); err != nil {
t.Fatal(err)
}
+ if c.Service == "SessionService" && c.Method == "New" {
+ body := want.(map[string]any)
+ metadata, _ := body["metadata"].(map[string]any)
+ if metadata == nil {
+ metadata = map[string]any{}
+ }
+ metadata["__qca_sdk_created"] = "true"
+ metadata["__qca_sdk_language"] = "go"
+ metadata["__qca_sdk_version"] = r.Header.Get("X-Qoder-Package-Version")
+ body["metadata"] = metadata
+ }
if !reflect.DeepEqual(got, want) {
t.Errorf("%s request body\n got: %s\nwant: %s", c.Doc, actual, c.Body)
}
diff --git a/managed/session.go b/managed/session.go
index 8fe0271..3c9df5f 100644
--- a/managed/session.go
+++ b/managed/session.go
@@ -46,7 +46,7 @@ func NewSessionService(opts ...option.RequestOption) (r SessionService) {
return
}
-// Create Session
+// Create Session. Adds __qca_sdk_ metadata; conflicting reserved values fail before sending.
func (r *SessionService) New(ctx context.Context, params SessionNewParams, opts ...option.RequestOption) (res *ManagedAgentsSession, err error) {
for _, v := range params.Betas {
opts = append(opts, option.WithHeaderAdd("x-qoder-beta", fmt.Sprintf("%v", v)))
@@ -54,7 +54,7 @@ func (r *SessionService) New(ctx context.Context, params SessionNewParams, opts
opts = slices.Concat(r.Options, opts)
path := "sessions"
- err = requestconfig.ExecuteNewRequest(ctx, http.MethodPost, path, params, &res, opts...)
+ err = requestconfig.ExecuteNewSessionRequest(ctx, http.MethodPost, path, params, &res, opts...)
return res, err
}
diff --git a/managed/test_helpers_test.go b/managed/test_helpers_test.go
index 86739c1..39df09b 100644
--- a/managed/test_helpers_test.go
+++ b/managed/test_helpers_test.go
@@ -51,7 +51,7 @@ func services(v reflect.Value, into map[string]reflect.Value) {
}
// Contract fixtures come from official documentation, independently of the adapted services.
-// The inventory also detects extra HTTP methods outside the authorized 106 endpoints.
+// The inventory also detects extra HTTP methods outside the authorized 107 endpoints.
func checkFields(t *testing.T, v reflect.Value, path string) {
t.Helper()
diff --git a/managed/testdata/api-contracts.json b/managed/testdata/api-contracts.json
index 6da29a7..87fc408 100644
--- a/managed/testdata/api-contracts.json
+++ b/managed/testdata/api-contracts.json
@@ -3156,5 +3156,19 @@
"next_page": null,
"total": null
}
+ },
+ {
+ "service": "OAuthService",
+ "name": "Start",
+ "method": "POST",
+ "path": "/oauth/start",
+ "file": "managed/oauth.go",
+ "doc": "oauth/start.md",
+ "route": "/oauth/start",
+ "response": {
+ "authorization_url": "https://mcp.example.com/authorize?state=opaque",
+ "state": "opaque",
+ "callback_origin": "https://console.example.com"
+ }
}
]