From 5c02339e559f4bb10ed32ffa907600e73896f06f Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 3 Nov 2026 16:17:15 +0800
Subject: [PATCH 1/2] fix: align session and resource contracts with QCA docs
---
CHANGELOG.md | 23 ++
docs/api/reference.md | 443 +++++++++++++++++++-----
forward/documentation_alignment_test.go | 179 ++++++++++
forward/environment.go | 21 +-
forward/params.go | 5 +
forward/session.go | 45 ++-
forward/sessionevent.go | 147 +++++---
managed/documentation_alignment_test.go | 87 +++++
managed/environment.go | 81 +++--
managed/memorystorememory.go | 8 +
managed/memorystorememoryversion.go | 10 +-
managed/session.go | 19 +-
managed/sessionthread.go | 25 +-
managed/vault.go | 3 +
14 files changed, 903 insertions(+), 193 deletions(-)
create mode 100644 forward/documentation_alignment_test.go
create mode 100644 managed/documentation_alignment_test.go
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7494e1e..f05b67e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,29 @@ existing `0.1.0` release; earlier development prereleases are not listed.
## [Unreleased]
+### Added
+
+- Add typed Forward Session budgets across create/update responses and events, including omission, explicit null clearing and decimal-string limits.
+- Add Forward Session `config.model` overrides and model `speed` configuration, plus optional approval evaluation details, Outcome/status event fields and cumulative top-level Credits on `session.usage`.
+- Add `startup_script` to Forward/Managed Environment models and Managed cloud/self-hosted parameters. It runs on sandbox start/resume; the external worker controls self-hosted execution.
+- Add Managed Memory `version`, version `redacted`, and Vault creation-response `credentials` fields. Vault creation still does not accept credentials in its request.
+
+### Fixed
+
+- Decode Forward event `evaluated_permission` as a string and align Managed Thread/coordinator nested model effort and context-window fields.
+- Add the current Memory version `updated` operation and list-item metadata/version fields; retain the legacy `Modified` constant as deprecated.
+
+### Breaking changes
+
+- Forward `SessionEvent.EvaluatedPermission` and the Managed Thread/coordinator union model `Effort` fields now use strings instead of object types.
+
+### Migration
+
+- Compare `event.EvaluatedPermission` directly to `"allow"`, `"ask"` or `"deny"`; automatic approval details are under `event.Evaluation.EvaluatedPermission`.
+- Read nested model `Effort` directly as a string. Legacy Managed model `Speed` and Thread `Usage` remain available but deprecated; current Thread responses omit usage.
+- Use `param.NullStruct[forward.SessionBudgetParam]()` to clear a budget and `param.NullStruct[forward.ModelConfigUnionParam]()` to clear an update's model override. Omit the model on create to inherit.
+- Treat `session.usage` Credits as cumulative snapshots: replace the previous values rather than adding successive events.
+
### Changed
- Remove resource-specific sections and inventories from the README to keep it focused on SDK setup and shared client behavior.
diff --git a/docs/api/reference.md b/docs/api/reference.md
index ae46612..85b995a 100644
--- a/docs/api/reference.md
+++ b/docs/api/reference.md
@@ -796,6 +796,12 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [func \(r \*Session\) UnmarshalJSON\(data \[\]byte\) error](<#Session.UnmarshalJSON>)
- [type SessionArchiveParams](<#SessionArchiveParams>)
- [func \(r SessionArchiveParams\) URLQuery\(\) \(url.Values, error\)](<#SessionArchiveParams.URLQuery>)
+- [type SessionBudget](<#SessionBudget>)
+ - [func \(r SessionBudget\) RawJSON\(\) string](<#SessionBudget.RawJSON>)
+ - [func \(r \*SessionBudget\) UnmarshalJSON\(data \[\]byte\) error](<#SessionBudget.UnmarshalJSON>)
+- [type SessionBudgetParam](<#SessionBudgetParam>)
+ - [func \(r SessionBudgetParam\) MarshalJSON\(\) \(\[\]byte, error\)](<#SessionBudgetParam.MarshalJSON>)
+ - [func \(r \*SessionBudgetParam\) UnmarshalJSON\(data \[\]byte\) error](<#SessionBudgetParam.UnmarshalJSON>)
- [type SessionCancelParams](<#SessionCancelParams>)
- [func \(r SessionCancelParams\) URLQuery\(\) \(url.Values, error\)](<#SessionCancelParams.URLQuery>)
- [type SessionConfig](<#SessionConfig>)
@@ -1003,6 +1009,12 @@ import "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
- [type Tool](<#Tool>)
- [func \(r Tool\) RawJSON\(\) string](<#Tool.RawJSON>)
- [func \(r \*Tool\) UnmarshalJSON\(data \[\]byte\) error](<#Tool.UnmarshalJSON>)
+- [type ToolApprovalDecision](<#ToolApprovalDecision>)
+ - [func \(r ToolApprovalDecision\) RawJSON\(\) string](<#ToolApprovalDecision.RawJSON>)
+ - [func \(r \*ToolApprovalDecision\) UnmarshalJSON\(data \[\]byte\) error](<#ToolApprovalDecision.UnmarshalJSON>)
+- [type ToolApprovalEvaluation](<#ToolApprovalEvaluation>)
+ - [func \(r ToolApprovalEvaluation\) RawJSON\(\) string](<#ToolApprovalEvaluation.RawJSON>)
+ - [func \(r \*ToolApprovalEvaluation\) UnmarshalJSON\(data \[\]byte\) error](<#ToolApprovalEvaluation.UnmarshalJSON>)
- [type ToolConfig](<#ToolConfig>)
- [func \(r ToolConfig\) RawJSON\(\) string](<#ToolConfig.RawJSON>)
- [func \(r \*ToolConfig\) UnmarshalJSON\(data \[\]byte\) error](<#ToolConfig.UnmarshalJSON>)
@@ -4719,14 +4731,17 @@ func (r *EnvironmentBindingInfo) UnmarshalJSON(data []byte) error
```go
type EnvironmentConfig struct {
- SetupScript string `json:"setup_script"`
- Type string `json:"type"`
- Packages EnvironmentConfigPackages `json:"packages"`
- JSON struct {
- SetupScript respjson.Field
- Type respjson.Field
- Packages respjson.Field
- ExtraFields map[string]respjson.Field
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript string `json:"startup_script"`
+ SetupScript string `json:"setup_script"`
+ Type string `json:"type"`
+ Packages EnvironmentConfigPackages `json:"packages"`
+ JSON struct {
+ StartupScript respjson.Field
+ SetupScript respjson.Field
+ Type respjson.Field
+ Packages respjson.Field
+ ExtraFields map[string]respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -7936,10 +7951,13 @@ ModelConfig preserves either a model ID string or an object from the API. ID is
```go
type ModelConfig struct {
+ // Inference speed: standard or high, subject to model capabilities.
+ Speed string `json:"speed"`
ID string `json:"id"`
Effort string `json:"effort"`
ContextWindow int64 `json:"context_window"`
JSON struct {
+ Speed respjson.Field
ID respjson.Field
Effort respjson.Field
ContextWindow respjson.Field
@@ -7974,6 +7992,8 @@ func (r *ModelConfig) UnmarshalJSON(data []byte) error
```go
type ModelConfigParam struct {
+ // Inference speed: standard or high, subject to model capabilities.
+ Speed param.Opt[string] `json:"speed,omitzero"`
ID string `json:"id" api:"required"`
Effort param.Opt[string] `json:"effort,omitzero"`
ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
@@ -10716,6 +10736,8 @@ Revoke revokes a Forward SAT binding belonging to the same Service Account. Use
```go
type Session struct {
+ // Use JSON.Budget to distinguish absent, null (unlimited), and an object.
+ Budget SessionBudget `json:"budget" api:"nullable"`
OutcomeEvaluations []SessionOutcomeEvaluation `json:"outcome_evaluations"`
// Session ID.
ID string `json:"id"`
@@ -10739,6 +10761,7 @@ type Session struct {
CreatedAt time.Time `json:"created_at" format:"date-time"`
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
JSON struct {
+ Budget respjson.Field
OutcomeEvaluations respjson.Field
ID respjson.Field
Type respjson.Field
@@ -10801,6 +10824,73 @@ func (r SessionArchiveParams) URLQuery() (url.Values, error)
+
+## type [SessionBudget]()
+
+
+
+```go
+type SessionBudget struct {
+ Type string `json:"type"`
+ MaxCreditCost string `json:"max_credit_cost"`
+ JSON struct {
+ Type respjson.Field
+ MaxCreditCost respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(SessionBudget\) [RawJSON]()
+
+```go
+func (r SessionBudget) RawJSON() string
+```
+
+
+
+
+### func \(\*SessionBudget\) [UnmarshalJSON]()
+
+```go
+func (r *SessionBudget) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [SessionBudgetParam]()
+
+A cumulative model and sandbox Credits limit. MaxCreditCost is a positive decimal string. Once reached, the server rejects the next user message; an active turn can finish.
+
+```go
+type SessionBudgetParam struct {
+ Type string `json:"type" api:"required"`
+ MaxCreditCost string `json:"max_credit_cost" api:"required"`
+ // contains filtered or unexported fields
+}
+```
+
+
+### func \(SessionBudgetParam\) [MarshalJSON]()
+
+```go
+func (r SessionBudgetParam) MarshalJSON() ([]byte, error)
+```
+
+
+
+
+### func \(\*SessionBudgetParam\) [UnmarshalJSON]()
+
+```go
+func (r *SessionBudgetParam) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [SessionCancelParams]()
@@ -10830,8 +10920,10 @@ func (r SessionCancelParams) URLQuery() (url.Values, error)
```go
type SessionConfig struct {
+ Model ModelConfig `json:"model"`
EnvironmentVariables map[string]string `json:"environment_variables"`
JSON struct {
+ Model respjson.Field
EnvironmentVariables respjson.Field
ExtraFields map[string]respjson.Field
// contains filtered or unexported fields
@@ -10864,6 +10956,24 @@ func (r *SessionConfig) UnmarshalJSON(data []byte) error
```go
type SessionEvent struct {
+ // Cumulative total Credits.
+ TotalCredits float64 `json:"total_credits"`
+ // Cumulative sandbox Credits.
+ SandboxRuntimeCredits float64 `json:"sandbox_runtime_credits"`
+ // Cumulative model Credits; use the latest value, not a sum of events.
+ ModelCredits float64 `json:"model_credits"`
+ // Related outcome evaluation start event.
+ OutcomeEvaluationStartID string `json:"outcome_evaluation_start_id"`
+ // Outcome evaluation explanation.
+ Explanation string `json:"explanation"`
+ // Outcome evaluation iteration.
+ Iteration int64 `json:"iteration"`
+ // Optional status reason, such as outcome_evaluation.
+ Reason string `json:"reason"`
+ // Optional approval details; evaluated_permission at the event root is a string.
+ Evaluation ToolApprovalEvaluation `json:"evaluation"`
+ // Use JSON.Budget to distinguish absent, null (unlimited), and an object.
+ Budget SessionBudget `json:"budget" api:"nullable"`
ID string `json:"id"`
Type string `json:"type"`
SessionID string `json:"session_id"`
@@ -10895,7 +11005,7 @@ type SessionEvent struct {
Usage map[string]any `json:"usage"`
StopReason map[string]any `json:"stop_reason"`
Error map[string]any `json:"error"`
- EvaluatedPermission map[string]any `json:"evaluated_permission"`
+ EvaluatedPermission string `json:"evaluated_permission"`
FileID string `json:"file_id"`
OriginalFilename string `json:"original_filename"`
Size int64 `json:"size"`
@@ -10906,48 +11016,57 @@ type SessionEvent struct {
ModelRequestStartID string `json:"model_request_start_id"`
ModelUsage map[string]any `json:"model_usage"`
JSON struct {
- ID respjson.Field
- Type respjson.Field
- SessionID respjson.Field
- Content respjson.Field
- ProcessedAt respjson.Field
- SessionThreadID respjson.Field
- Thinking respjson.Field
- Text respjson.Field
- ToolUseID respjson.Field
- CustomToolUseID respjson.Field
- MCPToolUseID respjson.Field
- Name respjson.Field
- MCPServerName respjson.Field
- Input respjson.Field
- IsError respjson.Field
- Result respjson.Field
- DenyMessage respjson.Field
- Description respjson.Field
- Rubric respjson.Field
- OutcomeID respjson.Field
- MaxIterations respjson.Field
- MessageID respjson.Field
- Message respjson.Field
- Index respjson.Field
- ContentBlock respjson.Field
- Delta respjson.Field
- Event respjson.Field
- EventID respjson.Field
- Usage respjson.Field
- StopReason respjson.Field
- Error respjson.Field
- EvaluatedPermission respjson.Field
- FileID respjson.Field
- OriginalFilename respjson.Field
- Size respjson.Field
- ContentType respjson.Field
- Agent respjson.Field
- Metadata respjson.Field
- Title respjson.Field
- ModelRequestStartID respjson.Field
- ModelUsage respjson.Field
- ExtraFields map[string]respjson.Field
+ TotalCredits respjson.Field
+ SandboxRuntimeCredits respjson.Field
+ ModelCredits respjson.Field
+ OutcomeEvaluationStartID respjson.Field
+ Explanation respjson.Field
+ Iteration respjson.Field
+ Reason respjson.Field
+ Evaluation respjson.Field
+ Budget respjson.Field
+ ID respjson.Field
+ Type respjson.Field
+ SessionID respjson.Field
+ Content respjson.Field
+ ProcessedAt respjson.Field
+ SessionThreadID respjson.Field
+ Thinking respjson.Field
+ Text respjson.Field
+ ToolUseID respjson.Field
+ CustomToolUseID respjson.Field
+ MCPToolUseID respjson.Field
+ Name respjson.Field
+ MCPServerName respjson.Field
+ Input respjson.Field
+ IsError respjson.Field
+ Result respjson.Field
+ DenyMessage respjson.Field
+ Description respjson.Field
+ Rubric respjson.Field
+ OutcomeID respjson.Field
+ MaxIterations respjson.Field
+ MessageID respjson.Field
+ Message respjson.Field
+ Index respjson.Field
+ ContentBlock respjson.Field
+ Delta respjson.Field
+ Event respjson.Field
+ EventID respjson.Field
+ Usage respjson.Field
+ StopReason respjson.Field
+ Error respjson.Field
+ EvaluatedPermission respjson.Field
+ FileID respjson.Field
+ OriginalFilename respjson.Field
+ Size respjson.Field
+ ContentType respjson.Field
+ Agent respjson.Field
+ Metadata respjson.Field
+ Title respjson.Field
+ ModelRequestStartID respjson.Field
+ ModelUsage respjson.Field
+ ExtraFields map[string]respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -11278,6 +11397,8 @@ func (r SessionListParams) URLQuery() (url.Values, error)
```go
type SessionNewParams struct {
+ // Omit to keep the default/current budget; use param.NullStruct[SessionBudgetParam]() to clear.
+ Budget SessionBudgetParam `json:"budget,omitzero" api:"nullable"`
// Forward Identity ID.
IdentityID string `json:"identity_id" api:"required"`
// Forward Template ID.
@@ -11319,7 +11440,9 @@ func (r *SessionNewParams) UnmarshalJSON(data []byte) error
```go
type SessionNewParamsConfigParam struct {
- EnvironmentVariables map[string]any `json:"environment_variables,omitzero"`
+ // Model override. Omit on create to inherit; explicit null on update restores inheritance.
+ Model ModelConfigUnionParam `json:"model,omitzero"`
+ EnvironmentVariables map[string]any `json:"environment_variables,omitzero"`
// contains filtered or unexported fields
}
```
@@ -12122,6 +12245,8 @@ func (r *SessionThreadUsage) UnmarshalJSON(data []byte) error
```go
type SessionUpdateParams struct {
+ // Omit to keep the default/current budget; use param.NullStruct[SessionBudgetParam]() to clear.
+ Budget SessionBudgetParam `json:"budget,omitzero" api:"nullable"`
// New Session title.
Title param.Opt[string] `json:"title,omitzero"`
// Metadata merge patch; supplied keys overwrite existing keys, omitted keys are kept.
@@ -12158,7 +12283,9 @@ func (r *SessionUpdateParams) UnmarshalJSON(data []byte) error
```go
type SessionUpdateParamsConfigParam struct {
- EnvironmentVariables map[string]any `json:"environment_variables,omitzero"`
+ // Model override. Omit on create to inherit; explicit null on update restores inheritance.
+ Model ModelConfigUnionParam `json:"model,omitzero"`
+ EnvironmentVariables map[string]any `json:"environment_variables,omitzero"`
// contains filtered or unexported fields
}
```
@@ -13521,6 +13648,78 @@ func (r *Tool) UnmarshalJSON(data []byte) error
+
+## type [ToolApprovalDecision]()
+
+
+
+```go
+type ToolApprovalDecision struct {
+ Type string `json:"type"`
+ ReasonCode string `json:"reason_code"`
+ JSON struct {
+ Type respjson.Field
+ ReasonCode respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(ToolApprovalDecision\) [RawJSON]()
+
+```go
+func (r ToolApprovalDecision) RawJSON() string
+```
+
+
+
+
+### func \(\*ToolApprovalDecision\) [UnmarshalJSON]()
+
+```go
+func (r *ToolApprovalDecision) UnmarshalJSON(data []byte) error
+```
+
+
+
+
+## type [ToolApprovalEvaluation]()
+
+
+
+```go
+type ToolApprovalEvaluation struct {
+ Type string `json:"type"`
+ EvaluatedPermission ToolApprovalDecision `json:"evaluated_permission"`
+ JSON struct {
+ Type respjson.Field
+ EvaluatedPermission respjson.Field
+ ExtraFields map[string]respjson.Field
+ // contains filtered or unexported fields
+ } `json:"-"`
+}
+```
+
+
+### func \(ToolApprovalEvaluation\) [RawJSON]()
+
+```go
+func (r ToolApprovalEvaluation) RawJSON() string
+```
+
+
+
+
+### func \(\*ToolApprovalEvaluation\) [UnmarshalJSON]()
+
+```go
+func (r *ToolApprovalEvaluation) UnmarshalJSON(data []byte) error
+```
+
+
+
## type [ToolConfig]()
@@ -15245,6 +15444,7 @@ Qoder managed API definitions.
- [func \(u EnvironmentNewParamsConfigUnion\) GetNetworking\(\) \*CloudConfigParamsNetworkingUnion](<#EnvironmentNewParamsConfigUnion.GetNetworking>)
- [func \(u EnvironmentNewParamsConfigUnion\) GetPackages\(\) \*PackagesParams](<#EnvironmentNewParamsConfigUnion.GetPackages>)
- [func \(u EnvironmentNewParamsConfigUnion\) GetSetupScript\(\) \*string](<#EnvironmentNewParamsConfigUnion.GetSetupScript>)
+ - [func \(u EnvironmentNewParamsConfigUnion\) GetStartupScript\(\) \*string](<#EnvironmentNewParamsConfigUnion.GetStartupScript>)
- [func \(u EnvironmentNewParamsConfigUnion\) GetType\(\) \*string](<#EnvironmentNewParamsConfigUnion.GetType>)
- [func \(u EnvironmentNewParamsConfigUnion\) MarshalJSON\(\) \(\[\]byte, error\)](<#EnvironmentNewParamsConfigUnion.MarshalJSON>)
- [func \(u \*EnvironmentNewParamsConfigUnion\) UnmarshalJSON\(data \[\]byte\) error](<#EnvironmentNewParamsConfigUnion.UnmarshalJSON>)
@@ -15271,6 +15471,7 @@ Qoder managed API definitions.
- [func \(u EnvironmentUpdateParamsConfigUnion\) GetNetworking\(\) \*CloudConfigParamsNetworkingUnion](<#EnvironmentUpdateParamsConfigUnion.GetNetworking>)
- [func \(u EnvironmentUpdateParamsConfigUnion\) GetPackages\(\) \*PackagesParams](<#EnvironmentUpdateParamsConfigUnion.GetPackages>)
- [func \(u EnvironmentUpdateParamsConfigUnion\) GetSetupScript\(\) \*string](<#EnvironmentUpdateParamsConfigUnion.GetSetupScript>)
+ - [func \(u EnvironmentUpdateParamsConfigUnion\) GetStartupScript\(\) \*string](<#EnvironmentUpdateParamsConfigUnion.GetStartupScript>)
- [func \(u EnvironmentUpdateParamsConfigUnion\) GetType\(\) \*string](<#EnvironmentUpdateParamsConfigUnion.GetType>)
- [func \(u EnvironmentUpdateParamsConfigUnion\) MarshalJSON\(\) \(\[\]byte, error\)](<#EnvironmentUpdateParamsConfigUnion.MarshalJSON>)
- [func \(u \*EnvironmentUpdateParamsConfigUnion\) UnmarshalJSON\(data \[\]byte\) error](<#EnvironmentUpdateParamsConfigUnion.UnmarshalJSON>)
@@ -19981,8 +20182,10 @@ NewClient uses common authentication defaults and QODER\_BASE\_URL. Explicit opt
```go
type CloudConfig struct {
// Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
- Storage BucketStorage `json:"storage"`
- SetupScript string `json:"setup_script"`
+ Storage BucketStorage `json:"storage"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript string `json:"startup_script"`
+ SetupScript string `json:"setup_script"`
// Network configuration policy.
Networking CloudConfigNetworkingUnion `json:"networking" api:"required"`
// Package manager configuration.
@@ -19991,12 +20194,13 @@ 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
- Type respjson.Field
- ExtraFields map[string]respjson.Field
+ Storage respjson.Field
+ StartupScript respjson.Field
+ SetupScript respjson.Field
+ Networking respjson.Field
+ Packages respjson.Field
+ Type respjson.Field
+ ExtraFields map[string]respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -20115,8 +20319,10 @@ The property Type is required.
```go
type CloudConfigParams struct {
// 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"`
+ Storage BucketStorageParam `json:"storage,omitzero"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript param.Opt[string] `json:"startup_script,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.
@@ -23181,8 +23387,10 @@ Use the methods beginning with 'As' to cast the union to one of its variants.
```go
type EnvironmentConfigUnion struct {
// Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
- Storage BucketStorage `json:"storage"`
- SetupScript string `json:"setup_script"`
+ Storage BucketStorage `json:"storage"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript string `json:"startup_script"`
+ SetupScript string `json:"setup_script"`
// This field is from variant [CloudConfig].
Networking CloudConfigNetworkingUnion `json:"networking"`
// This field is from variant [CloudConfig].
@@ -23190,11 +23398,12 @@ 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
- Type respjson.Field
+ Storage respjson.Field
+ StartupScript respjson.Field
+ SetupScript respjson.Field
+ Networking respjson.Field
+ Packages respjson.Field
+ Type respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -23458,6 +23667,15 @@ func (u EnvironmentNewParamsConfigUnion) GetSetupScript() *string
Returns the setup script from the selected configuration, if present.
+
+### func \(EnvironmentNewParamsConfigUnion\) [GetStartupScript]()
+
+```go
+func (u EnvironmentNewParamsConfigUnion) GetStartupScript() *string
+```
+
+
+
### func \(EnvironmentNewParamsConfigUnion\) [GetType]()
@@ -23760,6 +23978,15 @@ func (u EnvironmentUpdateParamsConfigUnion) GetSetupScript() *string
Returns the setup script from the selected configuration, if present.
+
+### func \(EnvironmentUpdateParamsConfigUnion\) [GetStartupScript]()
+
+```go
+func (u EnvironmentUpdateParamsConfigUnion) GetStartupScript() *string
+```
+
+
+
### func \(EnvironmentUpdateParamsConfigUnion\) [GetType]()
@@ -37642,6 +37869,8 @@ A \`memory\` object: a single text document at a hierarchical path inside a memo
```go
type ManagedAgentsMemory struct {
+ // Current memory version, starting at 1. Absent on prefix entries.
+ Version int64 `json:"version"`
Metadata map[string]string `json:"metadata"`
// Unique identifier for this memory (a `mem_...` value). Stable across renames;
@@ -37678,6 +37907,7 @@ type ManagedAgentsMemory struct {
Content string `json:"content" api:"nullable"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
+ Version respjson.Field
Metadata respjson.Field
ID respjson.Field
@@ -37725,6 +37955,9 @@ Use the methods beginning with 'As' to cast the union to one of its variants.
```go
type ManagedAgentsMemoryListItemUnion struct {
+ Metadata map[string]string `json:"metadata"`
+ // Current memory version, starting at 1. Absent on prefix entries.
+ Version int64 `json:"version"`
// This field is from variant [ManagedAgentsMemory].
ID string `json:"id"`
// This field is from variant [ManagedAgentsMemory].
@@ -37745,6 +37978,8 @@ type ManagedAgentsMemoryListItemUnion struct {
// This field is from variant [ManagedAgentsMemory].
Content string `json:"content"`
JSON struct {
+ Metadata respjson.Field
+ Version respjson.Field
ID respjson.Field
ContentSha256 respjson.Field
ContentSizeBytes respjson.Field
@@ -38351,6 +38586,7 @@ A \`memory\_version\` object: one immutable, attributed row in a memory's append
```go
type ManagedAgentsMemoryVersion struct {
+ Redacted bool `json:"redacted"`
// Unique identifier for this version (a `memver_...` value).
ID string `json:"id" api:"required"`
// A timestamp in RFC 3339 format
@@ -38366,7 +38602,7 @@ type ManagedAgentsMemoryVersion struct {
// The kind of mutation a `memory_version` records. Every non-no-op mutation to a
// memory appends exactly one version row with one of these values.
//
- // Any of "created", "modified", "deleted".
+ // Any of "created", "updated", "deleted".
Operation ManagedAgentsMemoryVersionOperation `json:"operation" api:"required"`
// Any of "memory_version".
Type ManagedAgentsMemoryVersionType `json:"type" api:"required"`
@@ -38399,6 +38635,7 @@ type ManagedAgentsMemoryVersion struct {
RedactedBy ManagedAgentsActorUnion `json:"redacted_by"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
+ Redacted respjson.Field
ID respjson.Field
CreatedAt respjson.Field
MemoryID respjson.Field
@@ -38449,7 +38686,9 @@ type ManagedAgentsMemoryVersionOperation string
```go
const (
- ManagedAgentsMemoryVersionOperationCreated ManagedAgentsMemoryVersionOperation = "created"
+ ManagedAgentsMemoryVersionOperationCreated ManagedAgentsMemoryVersionOperation = "created"
+ ManagedAgentsMemoryVersionOperationUpdated ManagedAgentsMemoryVersionOperation = "updated"
+ // Deprecated: current API responses use Updated. Retained for legacy payloads.
ManagedAgentsMemoryVersionOperationModified ManagedAgentsMemoryVersionOperation = "modified"
ManagedAgentsMemoryVersionOperationDeleted ManagedAgentsMemoryVersionOperation = "deleted"
)
@@ -43494,22 +43733,27 @@ If the underlying value is not a json object, one of the following properties wi
```go
type ManagedAgentsSessionMultiagentCoordinatorAgentUnionModel struct {
+ EffectiveContextWindow int64 `json:"effective_context_window"`
+ ContextWindow int64 `json:"context_window"`
// This field will be present if the value is a [string] instead of an object.
OfString string `json:",inline"`
// This field is from variant [ManagedAgentsModelConfig].
ID ManagedAgentsModel `json:"id"`
// This field is from variant [ManagedAgentsModelConfig].
- Effort ManagedAgentsModelConfigEffortUnion `json:"effort"`
+ Effort string `json:"effort"`
// This field is from variant [ManagedAgentsModelConfig].
InferenceGeo string `json:"inference_geo"`
// This field is from variant [ManagedAgentsModelConfig].
+ // Deprecated: speed is no longer part of Managed model configuration.
Speed ManagedAgentsModelConfigSpeed `json:"speed"`
JSON struct {
- OfString respjson.Field
- ID respjson.Field
- Effort respjson.Field
- InferenceGeo respjson.Field
- Speed respjson.Field
+ EffectiveContextWindow respjson.Field
+ ContextWindow respjson.Field
+ OfString respjson.Field
+ ID respjson.Field
+ Effort respjson.Field
+ InferenceGeo respjson.Field
+ Speed respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -44481,8 +44725,8 @@ type ManagedAgentsSessionThread struct {
Type ManagedAgentsSessionThreadType `json:"type" api:"required"`
// A timestamp in RFC 3339 format
UpdatedAt time.Time `json:"updated_at" api:"required" format:"date-time"`
- // Cumulative token usage for a session thread across all turns.
- Usage ManagedAgentsSessionThreadUsage `json:"usage" api:"required"`
+ // Deprecated: current Thread responses do not include usage. Read Session Credits instead.
+ Usage ManagedAgentsSessionThreadUsage `json:"usage"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
ID respjson.Field
@@ -44981,22 +45225,27 @@ If the underlying value is not a json object, one of the following properties wi
```go
type ManagedAgentsSessionThreadAgentUnionModel struct {
+ EffectiveContextWindow int64 `json:"effective_context_window"`
+ ContextWindow int64 `json:"context_window"`
// This field will be present if the value is a [string] instead of an object.
OfString string `json:",inline"`
// This field is from variant [ManagedAgentsModelConfig].
ID ManagedAgentsModel `json:"id"`
// This field is from variant [ManagedAgentsModelConfig].
- Effort ManagedAgentsModelConfigEffortUnion `json:"effort"`
+ Effort string `json:"effort"`
// This field is from variant [ManagedAgentsModelConfig].
InferenceGeo string `json:"inference_geo"`
// This field is from variant [ManagedAgentsModelConfig].
+ // Deprecated: speed is no longer part of Managed model configuration.
Speed ManagedAgentsModelConfigSpeed `json:"speed"`
JSON struct {
- OfString respjson.Field
- ID respjson.Field
- Effort respjson.Field
- InferenceGeo respjson.Field
- Speed respjson.Field
+ EffectiveContextWindow respjson.Field
+ ContextWindow respjson.Field
+ OfString respjson.Field
+ ID respjson.Field
+ Effort respjson.Field
+ InferenceGeo respjson.Field
+ Speed respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -45521,7 +45770,7 @@ const (
## type [ManagedAgentsSessionThreadUsage]()
-Cumulative token usage for a session thread across all turns.
+Deprecated: current Thread responses do not include usage. Read Session Credits instead.
```go
type ManagedAgentsSessionThreadUsage struct {
@@ -51583,6 +51832,8 @@ A vault that stores credentials for use by agents during sessions.
```go
type ManagedAgentsVault struct {
+ // Empty on creation; add credentials using the separate Credential API.
+ Credentials []ManagedAgentsCredential `json:"credentials"`
// Unique identifier for the vault.
ID string `json:"id" api:"required"`
// A timestamp in RFC 3339 format
@@ -51599,6 +51850,7 @@ type ManagedAgentsVault struct {
UpdatedAt time.Time `json:"updated_at" api:"required" format:"date-time"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
+ Credentials respjson.Field
ID respjson.Field
ArchivedAt respjson.Field
CreatedAt respjson.Field
@@ -53087,7 +53339,7 @@ type MemoryStoreMemoryVersionListParams struct {
SessionID param.Opt[string] `query:"session_id,omitzero" json:"-"`
// Query parameter for operation
//
- // Any of "created", "modified", "deleted".
+ // Any of "created", "updated", "deleted".
Operation ManagedAgentsMemoryVersionOperation `query:"operation,omitzero" json:"-"`
// Query parameter for view
//
@@ -55120,14 +55372,17 @@ Configuration for self\-hosted environments.
```go
type SelfHostedConfig struct {
- SetupScript string `json:"setup_script"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript string `json:"startup_script"`
+ SetupScript string `json:"setup_script"`
// Environment type
Type constant.SelfHosted `json:"type" default:"self_hosted"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
- SetupScript respjson.Field
- Type respjson.Field
- ExtraFields map[string]respjson.Field
+ StartupScript respjson.Field
+ SetupScript respjson.Field
+ Type respjson.Field
+ ExtraFields map[string]respjson.Field
// contains filtered or unexported fields
} `json:"-"`
}
@@ -55160,7 +55415,9 @@ This struct has a constant value, construct it with [NewSelfHostedConfigParams](
```go
type SelfHostedConfigParams struct {
- SetupScript param.Opt[string] `json:"setup_script,omitzero"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript param.Opt[string] `json:"startup_script,omitzero"`
+ SetupScript param.Opt[string] `json:"setup_script,omitzero"`
// Environment type
Type constant.SelfHosted `json:"type" default:"self_hosted"`
// contains filtered or unexported fields
diff --git a/forward/documentation_alignment_test.go b/forward/documentation_alignment_test.go
new file mode 100644
index 0000000..ddc1f5d
--- /dev/null
+++ b/forward/documentation_alignment_test.go
@@ -0,0 +1,179 @@
+package forward_test
+
+import (
+ "context"
+ "encoding/json"
+ "fmt"
+ "io"
+ "net/http"
+ "reflect"
+ "strings"
+ "testing"
+
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/param"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/convention/ssestream"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/forward"
+)
+
+// Official Forward Session schemas and Environment schemas, retrieved 2026-11-03.
+func TestForwardDocumentationBudgetAndModelWire(t *testing.T) {
+ budget := forward.SessionBudgetParam{Type: "limit", MaxCreditCost: "100.00"}
+ model := forward.ModelConfigUnionParam{OfConfig: &forward.ModelConfigParam{ID: "ultimate", Speed: forward.String("high"), ContextWindow: forward.Int(200000)}}
+ for _, tc := range []struct {
+ name string
+ params forward.SessionUpdateParams
+ want string
+ }{
+ {"omit", forward.SessionUpdateParams{}, `{}`},
+ {"clear", forward.SessionUpdateParams{Budget: param.NullStruct[forward.SessionBudgetParam](), Config: forward.SessionUpdateParamsConfigParam{Model: param.NullStruct[forward.ModelConfigUnionParam]()}}, `{"budget":null,"config":{"model":null}}`},
+ {"replace", forward.SessionUpdateParams{Budget: budget, Config: forward.SessionUpdateParamsConfigParam{Model: model}}, `{"budget":{"type":"limit","max_credit_cost":"100.00"},"config":{"model":{"id":"ultimate","speed":"high","context_window":200000}}}`},
+ {"string", forward.SessionUpdateParams{Config: forward.SessionUpdateParamsConfigParam{Model: forward.ModelConfigUnionParam{OfString: forward.String("ultimate")}}}, `{"config":{"model":"ultimate"}}`},
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ client := testClient(func(r *http.Request) (*http.Response, error) {
+ raw, err := io.ReadAll(r.Body)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var got, want any
+ if err = json.Unmarshal(raw, &got); err != nil {
+ t.Fatal(err)
+ }
+ if err = json.Unmarshal([]byte(tc.want), &want); err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("got %s want %s", raw, tc.want)
+ }
+ return reply(r, 200, tc.want), nil
+ })
+ result, err := client.Sessions.Update(context.Background(), "s", tc.params)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if tc.name == "clear" && result.JSON.Budget.Raw() != "null" {
+ t.Fatal("lost explicit null")
+ }
+ if tc.name == "omit" && result.JSON.Budget.Raw() != "" {
+ t.Fatal("lost omission")
+ }
+ if tc.name == "replace" && (result.Budget.MaxCreditCost != "100.00" || result.Config.Model.Speed != "high") {
+ t.Fatalf("result=%+v", result)
+ }
+ if tc.name == "string" && result.Config.Model.ID != "ultimate" {
+ t.Fatal("string model lost")
+ }
+ })
+ }
+ metadata := map[string]any{"business": "kept"}
+ client := testClient(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 body["budget"].(map[string]any)["max_credit_cost"] != "100.00" {
+ t.Fatal(body)
+ }
+ if body["metadata"].(map[string]any)["__qca_sdk_created"] != "true" {
+ t.Fatal(body)
+ }
+ if body["config"].(map[string]any)["model"].(map[string]any)["speed"] != "high" {
+ t.Fatal(body)
+ }
+ return reply(r, 200, `{"id":"s"}`), nil
+ })
+ _, err := client.Sessions.New(context.Background(), forward.SessionNewParams{IdentityID: "idn", TemplateID: "tmpl", Budget: budget, Config: forward.SessionNewParamsConfigParam{Model: model}, Metadata: metadata})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(metadata) != 1 {
+ t.Fatal("mutated caller metadata")
+ }
+}
+
+func TestForwardDocumentationEventTypes(t *testing.T) {
+ for _, tc := range []struct{ decision, policy, reason string }{{"allow", "always_allow", ""}, {"ask", "always_ask", ""}, {"allow", "auto", ""}, {"ask", "auto", "indeterminate"}, {"deny", "auto", "high_risk"}} {
+ t.Run(tc.decision+tc.policy, func(t *testing.T) {
+ detail := map[string]any{"type": tc.policy}
+ if tc.policy == "auto" {
+ detail["evaluated_permission"] = map[string]any{"type": tc.decision, "reason_code": tc.reason}
+ }
+ raw, _ := json.Marshal(map[string]any{"evaluated_permission": tc.decision, "evaluation": detail, "future": 17})
+ var e forward.SessionEvent
+ if err := json.Unmarshal(raw, &e); err != nil {
+ t.Fatal(err)
+ }
+ if e.EvaluatedPermission != tc.decision || e.Evaluation.Type != tc.policy {
+ t.Fatal(e)
+ }
+ if tc.policy == "auto" && (e.Evaluation.EvaluatedPermission.Type != tc.decision || e.Evaluation.EvaluatedPermission.ReasonCode != tc.reason) {
+ t.Fatal(e.Evaluation)
+ }
+ if e.JSON.ExtraFields["future"].Raw() != "17" {
+ t.Fatal("unknown field lost")
+ }
+ })
+ }
+ for _, raw := range []string{`{}`, `{"budget":null}`, `{"budget":{"type":"limit","max_credit_cost":"0.01"}}`} {
+ var e forward.SessionEvent
+ if err := json.Unmarshal([]byte(raw), &e); err != nil {
+ t.Fatal(err)
+ }
+ if strings.Contains(raw, "null") && e.JSON.Budget.Raw() != "null" {
+ t.Fatal("null budget lost")
+ }
+ if raw == `{}` && e.JSON.Budget.Raw() != "" {
+ t.Fatal("missing budget lost")
+ }
+ if strings.Contains(raw, "0.01") && e.Budget.MaxCreditCost != "0.01" {
+ t.Fatal(e.Budget)
+ }
+ }
+ payloads := []string{`{"id":"1","type":"session.usage","model_credits":0,"sandbox_runtime_credits":0,"total_credits":0}`, `{"id":"2","type":"session.usage","model_credits":0.68,"sandbox_runtime_credits":0.04,"total_credits":0.72}`, `{"id":"3","type":"session.status_idle","reason":"outcome_evaluation"}`, `{"id":"4","type":"span.outcome_evaluation_end","iteration":2,"explanation":"done","outcome_evaluation_start_id":"start"}`}
+ client := testClient(func(r *http.Request) (*http.Response, error) {
+ if strings.HasSuffix(r.URL.Path, "/stream") {
+ var b strings.Builder
+ for i, p := range payloads {
+ fmt.Fprintf(&b, "id: %d\ndata: %s\n\n", i, p)
+ }
+ res := reply(r, 200, b.String())
+ res.Header.Set("Content-Type", "text/event-stream")
+ return res, nil
+ }
+ return reply(r, 200, `{"data":[`+strings.Join(payloads, ",")+`],"has_more":false}`), nil
+ })
+ for _, thread := range []bool{false, true} {
+ var stream *ssestream.Stream[forward.SessionEvent]
+ if thread {
+ stream = client.Sessions.Threads.Events.StreamEvents(context.Background(), "s", "t", forward.SessionThreadEventStreamParams{})
+ } else {
+ stream = client.Sessions.Events.StreamEvents(context.Background(), "s", forward.SessionEventStreamParams{})
+ }
+ var got []forward.SessionEvent
+ for stream.Next() {
+ got = append(got, stream.Current())
+ }
+ err := stream.Err()
+ stream.Close()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(got) != 4 || !got[0].JSON.TotalCredits.Valid() || got[1].TotalCredits != 0.72 || got[1].ModelCredits != 0.68 || got[1].SandboxRuntimeCredits != 0.04 || got[2].Reason != "outcome_evaluation" || got[3].Iteration != 2 || got[3].Explanation != "done" || got[3].OutcomeEvaluationStartID != "start" {
+ t.Fatalf("events=%+v", got)
+ }
+ }
+ page, err := client.Sessions.Events.List(context.Background(), "s", forward.SessionEventListParams{})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if page.Data[1].TotalCredits != 0.72 {
+ t.Fatal("history type differs")
+ }
+ var env forward.Environment
+ if err = json.Unmarshal([]byte(`{"config":{"type":"cloud","startup_script":"echo ready"}}`), &env); err != nil {
+ t.Fatal(err)
+ }
+ if env.Config.StartupScript != "echo ready" {
+ t.Fatal("missing startup script")
+ }
+}
diff --git a/forward/environment.go b/forward/environment.go
index c04d8c2..0e72370 100644
--- a/forward/environment.go
+++ b/forward/environment.go
@@ -211,15 +211,18 @@ func (r Environment) RawJSON() string { return r.JSON.raw }
func (r *Environment) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type EnvironmentConfig struct {
- SetupScript string `json:"setup_script"`
- Type string `json:"type"`
- Packages EnvironmentConfigPackages `json:"packages"`
- JSON struct {
- SetupScript respjson.Field
- Type respjson.Field
- Packages respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript string `json:"startup_script"`
+ SetupScript string `json:"setup_script"`
+ Type string `json:"type"`
+ Packages EnvironmentConfigPackages `json:"packages"`
+ JSON struct {
+ StartupScript respjson.Field
+ SetupScript respjson.Field
+ Type respjson.Field
+ Packages respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
} `json:"-"`
}
diff --git a/forward/params.go b/forward/params.go
index fee34ca..c259018 100644
--- a/forward/params.go
+++ b/forward/params.go
@@ -35,10 +35,13 @@ func WithIdentityID(identityID string) option.RequestOption {
// ModelConfig preserves either a model ID string or an object from the API.
// ID is populated for both shapes; RawJSON retains the original representation.
type ModelConfig struct {
+ // Inference speed: standard or high, subject to model capabilities.
+ Speed string `json:"speed"`
ID string `json:"id"`
Effort string `json:"effort"`
ContextWindow int64 `json:"context_window"`
JSON struct {
+ Speed respjson.Field
ID respjson.Field
Effort respjson.Field
ContextWindow respjson.Field
@@ -51,6 +54,8 @@ func (r ModelConfig) RawJSON() string { return r.JSON.raw }
func (r *ModelConfig) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type ModelConfigParam struct {
+ // Inference speed: standard or high, subject to model capabilities.
+ Speed param.Opt[string] `json:"speed,omitzero"`
ID string `json:"id" api:"required"`
Effort param.Opt[string] `json:"effort,omitzero"`
ContextWindow param.Opt[int64] `json:"context_window,omitzero"`
diff --git a/forward/session.go b/forward/session.go
index b8d42fa..fdc6e0a 100644
--- a/forward/session.go
+++ b/forward/session.go
@@ -104,6 +104,8 @@ func (r *SessionService) New(ctx context.Context, params SessionNewParams, opts
}
type SessionNewParams struct {
+ // Omit to keep the default/current budget; use param.NullStruct[SessionBudgetParam]() to clear.
+ Budget SessionBudgetParam `json:"budget,omitzero" api:"nullable"`
// Forward Identity ID.
IdentityID string `json:"identity_id" api:"required"`
// Forward Template ID.
@@ -126,7 +128,9 @@ func (r SessionNewParams) MarshalJSON() ([]byte, error) {
func (r *SessionNewParams) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type SessionNewParamsConfigParam struct {
- EnvironmentVariables map[string]any `json:"environment_variables,omitzero"`
+ // Model override. Omit on create to inherit; explicit null on update restores inheritance.
+ Model ModelConfigUnionParam `json:"model,omitzero"`
+ EnvironmentVariables map[string]any `json:"environment_variables,omitzero"`
paramObj
}
@@ -165,6 +169,8 @@ func (r *SessionService) Update(ctx context.Context, sessionID string, params Se
}
type SessionUpdateParams struct {
+ // Omit to keep the default/current budget; use param.NullStruct[SessionBudgetParam]() to clear.
+ Budget SessionBudgetParam `json:"budget,omitzero" api:"nullable"`
// New Session title.
Title param.Opt[string] `json:"title,omitzero"`
// Metadata merge patch; supplied keys overwrite existing keys, omitted keys are kept.
@@ -182,7 +188,9 @@ func (r SessionUpdateParams) MarshalJSON() ([]byte, error) {
func (r *SessionUpdateParams) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type SessionUpdateParamsConfigParam struct {
- EnvironmentVariables map[string]any `json:"environment_variables,omitzero"`
+ // Model override. Omit on create to inherit; explicit null on update restores inheritance.
+ Model ModelConfigUnionParam `json:"model,omitzero"`
+ EnvironmentVariables map[string]any `json:"environment_variables,omitzero"`
paramObj
}
@@ -243,6 +251,8 @@ func (r SessionCancelParams) URLQuery() (url.Values, error) {
}
type Session struct {
+ // Use JSON.Budget to distinguish absent, null (unlimited), and an object.
+ Budget SessionBudget `json:"budget" api:"nullable"`
OutcomeEvaluations []SessionOutcomeEvaluation `json:"outcome_evaluations"`
// Session ID.
ID string `json:"id"`
@@ -266,6 +276,7 @@ type Session struct {
CreatedAt time.Time `json:"created_at" format:"date-time"`
UpdatedAt time.Time `json:"updated_at" format:"date-time"`
JSON struct {
+ Budget respjson.Field
OutcomeEvaluations respjson.Field
ID respjson.Field
Type respjson.Field
@@ -321,8 +332,10 @@ func (r SessionStats) RawJSON() string { return r.JSON.raw }
func (r *SessionStats) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
type SessionConfig struct {
+ Model ModelConfig `json:"model"`
EnvironmentVariables map[string]string `json:"environment_variables"`
JSON struct {
+ Model respjson.Field
EnvironmentVariables respjson.Field
ExtraFields map[string]respjson.Field
raw string
@@ -377,3 +390,31 @@ func (r SessionOutcomeEvaluation) RawJSON() string { return r.JSON.raw }
func (r *SessionOutcomeEvaluation) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+
+type SessionBudget struct {
+ Type string `json:"type"`
+ MaxCreditCost string `json:"max_credit_cost"`
+ JSON struct {
+ Type respjson.Field
+ MaxCreditCost respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r SessionBudget) RawJSON() string { return r.JSON.raw }
+func (r *SessionBudget) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
+
+// A cumulative model and sandbox Credits limit. MaxCreditCost is a positive decimal string.
+// Once reached, the server rejects the next user message; an active turn can finish.
+type SessionBudgetParam struct {
+ Type string `json:"type" api:"required"`
+ MaxCreditCost string `json:"max_credit_cost" api:"required"`
+ paramObj
+}
+
+func (r SessionBudgetParam) MarshalJSON() ([]byte, error) {
+ type shadow SessionBudgetParam
+ return param.MarshalObject(r, (*shadow)(&r))
+}
+func (r *SessionBudgetParam) UnmarshalJSON(data []byte) error { return apijson.UnmarshalRoot(data, r) }
diff --git a/forward/sessionevent.go b/forward/sessionevent.go
index d754e17..2d6f293 100644
--- a/forward/sessionevent.go
+++ b/forward/sessionevent.go
@@ -139,6 +139,24 @@ func (r SessionEventStreamParams) URLQuery() (url.Values, error) {
}
type SessionEvent struct {
+ // Cumulative total Credits.
+ TotalCredits float64 `json:"total_credits"`
+ // Cumulative sandbox Credits.
+ SandboxRuntimeCredits float64 `json:"sandbox_runtime_credits"`
+ // Cumulative model Credits; use the latest value, not a sum of events.
+ ModelCredits float64 `json:"model_credits"`
+ // Related outcome evaluation start event.
+ OutcomeEvaluationStartID string `json:"outcome_evaluation_start_id"`
+ // Outcome evaluation explanation.
+ Explanation string `json:"explanation"`
+ // Outcome evaluation iteration.
+ Iteration int64 `json:"iteration"`
+ // Optional status reason, such as outcome_evaluation.
+ Reason string `json:"reason"`
+ // Optional approval details; evaluated_permission at the event root is a string.
+ Evaluation ToolApprovalEvaluation `json:"evaluation"`
+ // Use JSON.Budget to distinguish absent, null (unlimited), and an object.
+ Budget SessionBudget `json:"budget" api:"nullable"`
ID string `json:"id"`
Type string `json:"type"`
SessionID string `json:"session_id"`
@@ -170,7 +188,7 @@ type SessionEvent struct {
Usage map[string]any `json:"usage"`
StopReason map[string]any `json:"stop_reason"`
Error map[string]any `json:"error"`
- EvaluatedPermission map[string]any `json:"evaluated_permission"`
+ EvaluatedPermission string `json:"evaluated_permission"`
FileID string `json:"file_id"`
OriginalFilename string `json:"original_filename"`
Size int64 `json:"size"`
@@ -181,49 +199,58 @@ type SessionEvent struct {
ModelRequestStartID string `json:"model_request_start_id"`
ModelUsage map[string]any `json:"model_usage"`
JSON struct {
- ID respjson.Field
- Type respjson.Field
- SessionID respjson.Field
- Content respjson.Field
- ProcessedAt respjson.Field
- SessionThreadID respjson.Field
- Thinking respjson.Field
- Text respjson.Field
- ToolUseID respjson.Field
- CustomToolUseID respjson.Field
- MCPToolUseID respjson.Field
- Name respjson.Field
- MCPServerName respjson.Field
- Input respjson.Field
- IsError respjson.Field
- Result respjson.Field
- DenyMessage respjson.Field
- Description respjson.Field
- Rubric respjson.Field
- OutcomeID respjson.Field
- MaxIterations respjson.Field
- MessageID respjson.Field
- Message respjson.Field
- Index respjson.Field
- ContentBlock respjson.Field
- Delta respjson.Field
- Event respjson.Field
- EventID respjson.Field
- Usage respjson.Field
- StopReason respjson.Field
- Error respjson.Field
- EvaluatedPermission respjson.Field
- FileID respjson.Field
- OriginalFilename respjson.Field
- Size respjson.Field
- ContentType respjson.Field
- Agent respjson.Field
- Metadata respjson.Field
- Title respjson.Field
- ModelRequestStartID respjson.Field
- ModelUsage respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
+ TotalCredits respjson.Field
+ SandboxRuntimeCredits respjson.Field
+ ModelCredits respjson.Field
+ OutcomeEvaluationStartID respjson.Field
+ Explanation respjson.Field
+ Iteration respjson.Field
+ Reason respjson.Field
+ Evaluation respjson.Field
+ Budget respjson.Field
+ ID respjson.Field
+ Type respjson.Field
+ SessionID respjson.Field
+ Content respjson.Field
+ ProcessedAt respjson.Field
+ SessionThreadID respjson.Field
+ Thinking respjson.Field
+ Text respjson.Field
+ ToolUseID respjson.Field
+ CustomToolUseID respjson.Field
+ MCPToolUseID respjson.Field
+ Name respjson.Field
+ MCPServerName respjson.Field
+ Input respjson.Field
+ IsError respjson.Field
+ Result respjson.Field
+ DenyMessage respjson.Field
+ Description respjson.Field
+ Rubric respjson.Field
+ OutcomeID respjson.Field
+ MaxIterations respjson.Field
+ MessageID respjson.Field
+ Message respjson.Field
+ Index respjson.Field
+ ContentBlock respjson.Field
+ Delta respjson.Field
+ Event respjson.Field
+ EventID respjson.Field
+ Usage respjson.Field
+ StopReason respjson.Field
+ Error respjson.Field
+ EvaluatedPermission respjson.Field
+ FileID respjson.Field
+ OriginalFilename respjson.Field
+ Size respjson.Field
+ ContentType respjson.Field
+ Agent respjson.Field
+ Metadata respjson.Field
+ Title respjson.Field
+ ModelRequestStartID respjson.Field
+ ModelUsage respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
} `json:"-"`
}
@@ -243,3 +270,35 @@ func (r SessionEventSendResponse) RawJSON() string { return r.JSON.raw }
func (r *SessionEventSendResponse) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+
+type ToolApprovalEvaluation struct {
+ Type string `json:"type"`
+ EvaluatedPermission ToolApprovalDecision `json:"evaluated_permission"`
+ JSON struct {
+ Type respjson.Field
+ EvaluatedPermission respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r ToolApprovalEvaluation) RawJSON() string { return r.JSON.raw }
+func (r *ToolApprovalEvaluation) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
+
+type ToolApprovalDecision struct {
+ Type string `json:"type"`
+ ReasonCode string `json:"reason_code"`
+ JSON struct {
+ Type respjson.Field
+ ReasonCode respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
+ } `json:"-"`
+}
+
+func (r ToolApprovalDecision) RawJSON() string { return r.JSON.raw }
+func (r *ToolApprovalDecision) UnmarshalJSON(data []byte) error {
+ return apijson.UnmarshalRoot(data, r)
+}
diff --git a/managed/documentation_alignment_test.go b/managed/documentation_alignment_test.go
new file mode 100644
index 0000000..32e8f00
--- /dev/null
+++ b/managed/documentation_alignment_test.go
@@ -0,0 +1,87 @@
+package managed_test
+
+import (
+ "encoding/json"
+ "github.com/QoderAI/qoder-cloud-agents-sdk-go/managed"
+ "testing"
+)
+
+// Official Memory Store, Vault and Environment schemas, retrieved 2026-11-03.
+func TestManagedDocumentationResponses(t *testing.T) {
+ var memory managed.ManagedAgentsMemory
+ raw := []byte(`{"type":"memory","version":2,"metadata":{"source":"test"}}`)
+ if err := json.Unmarshal(raw, &memory); err != nil {
+ t.Fatal(err)
+ }
+ if memory.Version != 2 || !memory.JSON.Version.Valid() {
+ t.Fatal(memory)
+ }
+ var item managed.ManagedAgentsMemoryListItemUnion
+ if err := json.Unmarshal(raw, &item); err != nil {
+ t.Fatal(err)
+ }
+ if item.Version != 2 || item.Metadata["source"] != "test" || item.AsMemory().Version != 2 {
+ t.Fatal(item)
+ }
+ for _, redacted := range []string{"false", "true"} {
+ var version managed.ManagedAgentsMemoryVersion
+ if err := json.Unmarshal([]byte(`{"operation":"updated","redacted":`+redacted+`}`), &version); err != nil {
+ t.Fatal(err)
+ }
+ if version.Operation != managed.ManagedAgentsMemoryVersionOperationUpdated || !version.JSON.Redacted.Valid() || version.Redacted != (redacted == "true") {
+ t.Fatal(version)
+ }
+ }
+ var vault managed.ManagedAgentsVault
+ if err := json.Unmarshal([]byte(`{"credentials":[]}`), &vault); err != nil {
+ t.Fatal(err)
+ }
+ if !vault.JSON.Credentials.Valid() || vault.Credentials == nil || len(vault.Credentials) != 0 {
+ t.Fatal(vault)
+ }
+ for _, id := range []string{`"ultimate"`, `{"id":"ultimate","effort":"none","context_window":200000,"effective_context_window":180000}`} {
+ var thread managed.ManagedAgentsSessionThreadAgentUnionModel
+ var coordinator managed.ManagedAgentsSessionMultiagentCoordinatorAgentUnionModel
+ if err := json.Unmarshal([]byte(id), &thread); err != nil {
+ t.Fatal(err)
+ }
+ if err := json.Unmarshal([]byte(id), &coordinator); err != nil {
+ t.Fatal(err)
+ }
+ if id[0] == '{' && (thread.Effort != "none" || thread.ContextWindow != 200000 || thread.EffectiveContextWindow != 180000 || coordinator.Effort != "none" || coordinator.ContextWindow != 200000 || coordinator.EffectiveContextWindow != 180000) {
+ t.Fatal(thread, coordinator)
+ }
+ if id[0] == '"' && (thread.OfString != "ultimate" || coordinator.OfString != "ultimate") {
+ t.Fatal("string variant lost")
+ }
+ }
+ for _, kind := range []string{"cloud", "self_hosted"} {
+ var env managed.Environment
+ if err := json.Unmarshal([]byte(`{"config":{"type":"`+kind+`","startup_script":"echo ready"}}`), &env); err != nil {
+ t.Fatal(err)
+ }
+ if env.Config.StartupScript != "echo ready" {
+ t.Fatal(env)
+ }
+ }
+ for _, config := range []any{managed.CloudConfigParams{StartupScript: managed.String("echo ready")}, managed.SelfHostedConfigParams{StartupScript: managed.String("echo ready")}} {
+ raw, err := json.Marshal(config)
+ if err != nil {
+ t.Fatal(err)
+ }
+ var fields map[string]any
+ if err = json.Unmarshal(raw, &fields); err != nil {
+ t.Fatal(err)
+ }
+ if fields["startup_script"] != "echo ready" {
+ t.Fatal(string(raw))
+ }
+ }
+ var thread managed.ManagedAgentsSessionThread
+ if err := json.Unmarshal([]byte(`{"id":"t"}`), &thread); err != nil {
+ t.Fatal(err)
+ }
+ if thread.JSON.Usage.Valid() {
+ t.Fatal("usage must be optional")
+ }
+}
diff --git a/managed/environment.go b/managed/environment.go
index be27f34..27be334 100644
--- a/managed/environment.go
+++ b/managed/environment.go
@@ -148,8 +148,10 @@ func (r *EnvironmentService) Archive(ctx context.Context, environmentID string,
// `cloud` environment configuration.
type CloudConfig struct {
// Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
- Storage BucketStorage `json:"storage"`
- SetupScript string `json:"setup_script"`
+ Storage BucketStorage `json:"storage"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript string `json:"startup_script"`
+ SetupScript string `json:"setup_script"`
// Network configuration policy.
Networking CloudConfigNetworkingUnion `json:"networking" api:"required"`
// Package manager configuration.
@@ -158,13 +160,14 @@ 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
- Type respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
+ Storage respjson.Field
+ StartupScript respjson.Field
+ SetupScript respjson.Field
+ Networking respjson.Field
+ Packages respjson.Field
+ Type respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
} `json:"-"`
}
@@ -250,8 +253,10 @@ func (r *CloudConfigNetworkingUnion) UnmarshalJSON(data []byte) error {
// The property Type is required.
type CloudConfigParams struct {
// 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"`
+ Storage BucketStorageParam `json:"storage,omitzero"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript param.Opt[string] `json:"startup_script,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.
@@ -401,8 +406,10 @@ 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 {
// Set Betas to include "oss-bucket-2026-09-23" when buckets remain configured.
- Storage BucketStorage `json:"storage"`
- SetupScript string `json:"setup_script"`
+ Storage BucketStorage `json:"storage"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript string `json:"startup_script"`
+ SetupScript string `json:"setup_script"`
// This field is from variant [CloudConfig].
Networking CloudConfigNetworkingUnion `json:"networking"`
// This field is from variant [CloudConfig].
@@ -410,12 +417,13 @@ 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
- Type respjson.Field
- raw string
+ Storage respjson.Field
+ StartupScript respjson.Field
+ SetupScript respjson.Field
+ Networking respjson.Field
+ Packages respjson.Field
+ Type respjson.Field
+ raw string
} `json:"-"`
}
@@ -652,15 +660,18 @@ const (
// Configuration for self-hosted environments.
type SelfHostedConfig struct {
- SetupScript string `json:"setup_script"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript string `json:"startup_script"`
+ SetupScript string `json:"setup_script"`
// Environment type
Type constant.SelfHosted `json:"type" default:"self_hosted"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
- SetupScript respjson.Field
- Type respjson.Field
- ExtraFields map[string]respjson.Field
- raw string
+ StartupScript respjson.Field
+ SetupScript respjson.Field
+ Type respjson.Field
+ ExtraFields map[string]respjson.Field
+ raw string
} `json:"-"`
}
@@ -681,7 +692,9 @@ func NewSelfHostedConfigParams() SelfHostedConfigParams {
// This struct has a constant value, construct it with
// [NewSelfHostedConfigParams].
type SelfHostedConfigParams struct {
- SetupScript param.Opt[string] `json:"setup_script,omitzero"`
+ // Runs on sandbox start/resume; self-hosted execution depends on the worker.
+ StartupScript param.Opt[string] `json:"startup_script,omitzero"`
+ SetupScript param.Opt[string] `json:"setup_script,omitzero"`
// Environment type
Type constant.SelfHosted `json:"type" default:"self_hosted"`
paramObj
@@ -1052,3 +1065,21 @@ func (r EnvironmentSearchParams) MarshalJSON() ([]byte, error) {
func (r *EnvironmentSearchParams) UnmarshalJSON(data []byte) error {
return apijson.UnmarshalRoot(data, r)
}
+
+func (u EnvironmentNewParamsConfigUnion) GetStartupScript() *string {
+ if v := u.OfCloud; v != nil && v.StartupScript.Valid() {
+ return &v.StartupScript.Value
+ } else if v := u.OfSelfHosted; v != nil && v.StartupScript.Valid() {
+ return &v.StartupScript.Value
+ }
+ return nil
+}
+
+func (u EnvironmentUpdateParamsConfigUnion) GetStartupScript() *string {
+ if v := u.OfCloud; v != nil && v.StartupScript.Valid() {
+ return &v.StartupScript.Value
+ } else if v := u.OfSelfHosted; v != nil && v.StartupScript.Valid() {
+ return &v.StartupScript.Value
+ }
+ return nil
+}
diff --git a/managed/memorystorememory.go b/managed/memorystorememory.go
index a6c0b49..82e0aaf 100644
--- a/managed/memorystorememory.go
+++ b/managed/memorystorememory.go
@@ -184,6 +184,8 @@ const (
// addressed by their `mem_...` ID; the path is the create key and can be changed
// via update.
type ManagedAgentsMemory struct {
+ // Current memory version, starting at 1. Absent on prefix entries.
+ Version int64 `json:"version"`
Metadata map[string]string `json:"metadata"`
// Unique identifier for this memory (a `mem_...` value). Stable across renames;
@@ -220,6 +222,7 @@ type ManagedAgentsMemory struct {
Content string `json:"content" api:"nullable"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
+ Version respjson.Field
Metadata respjson.Field
ID respjson.Field
@@ -257,6 +260,9 @@ const (
//
// Use the methods beginning with 'As' to cast the union to one of its variants.
type ManagedAgentsMemoryListItemUnion struct {
+ Metadata map[string]string `json:"metadata"`
+ // Current memory version, starting at 1. Absent on prefix entries.
+ Version int64 `json:"version"`
// This field is from variant [ManagedAgentsMemory].
ID string `json:"id"`
// This field is from variant [ManagedAgentsMemory].
@@ -277,6 +283,8 @@ type ManagedAgentsMemoryListItemUnion struct {
// This field is from variant [ManagedAgentsMemory].
Content string `json:"content"`
JSON struct {
+ Metadata respjson.Field
+ Version respjson.Field
ID respjson.Field
ContentSha256 respjson.Field
ContentSizeBytes respjson.Field
diff --git a/managed/memorystorememoryversion.go b/managed/memorystorememoryversion.go
index 4f36164..489c395 100644
--- a/managed/memorystorememoryversion.go
+++ b/managed/memorystorememoryversion.go
@@ -239,6 +239,7 @@ const (
// `content_size_bytes`, and `content_sha256` set to `null`; branch on
// `redacted_at`, not HTTP status.
type ManagedAgentsMemoryVersion struct {
+ Redacted bool `json:"redacted"`
// Unique identifier for this version (a `memver_...` value).
ID string `json:"id" api:"required"`
// A timestamp in RFC 3339 format
@@ -254,7 +255,7 @@ type ManagedAgentsMemoryVersion struct {
// The kind of mutation a `memory_version` records. Every non-no-op mutation to a
// memory appends exactly one version row with one of these values.
//
- // Any of "created", "modified", "deleted".
+ // Any of "created", "updated", "deleted".
Operation ManagedAgentsMemoryVersionOperation `json:"operation" api:"required"`
// Any of "memory_version".
Type ManagedAgentsMemoryVersionType `json:"type" api:"required"`
@@ -287,6 +288,7 @@ type ManagedAgentsMemoryVersion struct {
RedactedBy ManagedAgentsActorUnion `json:"redacted_by"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
+ Redacted respjson.Field
ID respjson.Field
CreatedAt respjson.Field
MemoryID respjson.Field
@@ -322,7 +324,9 @@ const (
type ManagedAgentsMemoryVersionOperation string
const (
- ManagedAgentsMemoryVersionOperationCreated ManagedAgentsMemoryVersionOperation = "created"
+ ManagedAgentsMemoryVersionOperationCreated ManagedAgentsMemoryVersionOperation = "created"
+ ManagedAgentsMemoryVersionOperationUpdated ManagedAgentsMemoryVersionOperation = "updated"
+ // Deprecated: current API responses use Updated. Retained for legacy payloads.
ManagedAgentsMemoryVersionOperationModified ManagedAgentsMemoryVersionOperation = "modified"
ManagedAgentsMemoryVersionOperationDeleted ManagedAgentsMemoryVersionOperation = "deleted"
)
@@ -444,7 +448,7 @@ type MemoryStoreMemoryVersionListParams struct {
SessionID param.Opt[string] `query:"session_id,omitzero" json:"-"`
// Query parameter for operation
//
- // Any of "created", "modified", "deleted".
+ // Any of "created", "updated", "deleted".
Operation ManagedAgentsMemoryVersionOperation `query:"operation,omitzero" json:"-"`
// Query parameter for view
//
diff --git a/managed/session.go b/managed/session.go
index 3c9df5f..bf6d2b1 100644
--- a/managed/session.go
+++ b/managed/session.go
@@ -1918,23 +1918,28 @@ func (r *ManagedAgentsSessionMultiagentCoordinatorAgentUnion) UnmarshalJSON(data
// If the underlying value is not a json object, one of the following properties
// will be valid: OfString]
type ManagedAgentsSessionMultiagentCoordinatorAgentUnionModel struct {
+ EffectiveContextWindow int64 `json:"effective_context_window"`
+ ContextWindow int64 `json:"context_window"`
// This field will be present if the value is a [string] instead of an object.
OfString string `json:",inline"`
// This field is from variant [ManagedAgentsModelConfig].
ID ManagedAgentsModel `json:"id"`
// This field is from variant [ManagedAgentsModelConfig].
- Effort ManagedAgentsModelConfigEffortUnion `json:"effort"`
+ Effort string `json:"effort"`
// This field is from variant [ManagedAgentsModelConfig].
InferenceGeo string `json:"inference_geo"`
// This field is from variant [ManagedAgentsModelConfig].
+ // Deprecated: speed is no longer part of Managed model configuration.
Speed ManagedAgentsModelConfigSpeed `json:"speed"`
JSON struct {
- OfString respjson.Field
- ID respjson.Field
- Effort respjson.Field
- InferenceGeo respjson.Field
- Speed respjson.Field
- raw string
+ EffectiveContextWindow respjson.Field
+ ContextWindow respjson.Field
+ OfString respjson.Field
+ ID respjson.Field
+ Effort respjson.Field
+ InferenceGeo respjson.Field
+ Speed respjson.Field
+ raw string
} `json:"-"`
}
diff --git a/managed/sessionthread.go b/managed/sessionthread.go
index 5d646aa..9896b85 100644
--- a/managed/sessionthread.go
+++ b/managed/sessionthread.go
@@ -137,8 +137,8 @@ type ManagedAgentsSessionThread struct {
Type ManagedAgentsSessionThreadType `json:"type" api:"required"`
// A timestamp in RFC 3339 format
UpdatedAt time.Time `json:"updated_at" api:"required" format:"date-time"`
- // Cumulative token usage for a session thread across all turns.
- Usage ManagedAgentsSessionThreadUsage `json:"usage" api:"required"`
+ // Deprecated: current Thread responses do not include usage. Read Session Credits instead.
+ Usage ManagedAgentsSessionThreadUsage `json:"usage"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
ID respjson.Field
@@ -262,23 +262,28 @@ func (r *ManagedAgentsSessionThreadAgentUnion) UnmarshalJSON(data []byte) error
// If the underlying value is not a json object, one of the following properties
// will be valid: OfString]
type ManagedAgentsSessionThreadAgentUnionModel struct {
+ EffectiveContextWindow int64 `json:"effective_context_window"`
+ ContextWindow int64 `json:"context_window"`
// This field will be present if the value is a [string] instead of an object.
OfString string `json:",inline"`
// This field is from variant [ManagedAgentsModelConfig].
ID ManagedAgentsModel `json:"id"`
// This field is from variant [ManagedAgentsModelConfig].
- Effort ManagedAgentsModelConfigEffortUnion `json:"effort"`
+ Effort string `json:"effort"`
// This field is from variant [ManagedAgentsModelConfig].
InferenceGeo string `json:"inference_geo"`
// This field is from variant [ManagedAgentsModelConfig].
+ // Deprecated: speed is no longer part of Managed model configuration.
Speed ManagedAgentsModelConfigSpeed `json:"speed"`
JSON struct {
- OfString respjson.Field
- ID respjson.Field
- Effort respjson.Field
- InferenceGeo respjson.Field
- Speed respjson.Field
- raw string
+ EffectiveContextWindow respjson.Field
+ ContextWindow respjson.Field
+ OfString respjson.Field
+ ID respjson.Field
+ Effort respjson.Field
+ InferenceGeo respjson.Field
+ Speed respjson.Field
+ raw string
} `json:"-"`
}
@@ -329,7 +334,7 @@ const (
ManagedAgentsSessionThreadStatusTerminated ManagedAgentsSessionThreadStatus = "terminated"
)
-// Cumulative token usage for a session thread across all turns.
+// Deprecated: current Thread responses do not include usage. Read Session Credits instead.
type ManagedAgentsSessionThreadUsage struct {
// Cumulative time in seconds this thread spent in running status. Equal to
// `stats.active_seconds`; surfaced here so a thread's usage carries every quantity
diff --git a/managed/vault.go b/managed/vault.go
index 2085990..912579d 100644
--- a/managed/vault.go
+++ b/managed/vault.go
@@ -155,6 +155,8 @@ const (
// A vault that stores credentials for use by agents during sessions.
type ManagedAgentsVault struct {
+ // Empty on creation; add credentials using the separate Credential API.
+ Credentials []ManagedAgentsCredential `json:"credentials"`
// Unique identifier for the vault.
ID string `json:"id" api:"required"`
// A timestamp in RFC 3339 format
@@ -171,6 +173,7 @@ type ManagedAgentsVault struct {
UpdatedAt time.Time `json:"updated_at" api:"required" format:"date-time"`
// JSON contains metadata for fields, check presence with [respjson.Field.Valid].
JSON struct {
+ Credentials respjson.Field
ID respjson.Field
ArchivedAt respjson.Field
CreatedAt respjson.Field
From 0eb3cd3ca13fb18eac987729c0e3a8389c4ea5fd Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 3 Nov 2026 16:51:29 +0800
Subject: [PATCH 2/2] docs(environments): explain startup script constraints
and failures
---
README.md | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/README.md b/README.md
index 7ae46b3..17fd9f4 100644
--- a/README.md
+++ b/README.md
@@ -15,6 +15,7 @@ The SDK ships two clients that share authentication, transport, retries, error h
- [Requirements](#requirements)
- [Usage](#usage)
- [PAT and Service Account authentication](#pat-and-service-account-authentication)
+- [Environment startup scripts](#environment-startup-scripts)
- [Streaming](#streaming)
- [Request fields](#request-fields)
- [Response objects](#response-objects)
@@ -160,6 +161,22 @@ cleanup verification, run `make test-live-sa-execution` with
independent; `QODER_AUTH_MODE` switches examples, not the PAT test suites.
See the [official authentication contract](https://docs.qoder.com/cloud-agents/api/conventions/authentication).
+## Environment startup scripts
+
+Both Forward and Managed accept `config.startup_script`. For cloud environments,
+it runs after `setup_script` on the first sandbox start and again on every resume,
+before the first tool call. The server enforces a 64 KB limit and a 5-minute
+timeout. Scripts must exit; start long-lived services in the background and wait
+for readiness when needed.
+
+Failure emits a `session.error` event whose `error.type` is
+`environment_startup_failed_error`; the session and sandbox remain usable.
+The script is not retried during the same start. For self-hosted environments,
+the API stores and returns the script; execution depends on the external worker.
+See the official [Forward](https://docs.qoder.com/cloud-agents/api/forward/environments/schemas#environment-startup-script)
+and [Managed](https://docs.qoder.com/cloud-agents/api/environments/schemas#environment-startup-script)
+contracts.
+
## Streaming
Streaming responses are consumed incrementally. Close the stream when finished and handle interruption explicitly; closing a local stream does not cancel server-side work.