diff options
| author | Dax <[email protected]> | 2025-07-13 17:22:11 -0400 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-07-13 17:22:11 -0400 |
| commit | 90d6c4ab41bb097d7db354109e3616ff16778f0b (patch) | |
| tree | 303861ce5789f6e0e8e843cb8184dea829b4885d /packages/tui/sdk | |
| parent | 736396fc70ab05204b886634ffbcd1318d82eca8 (diff) | |
| download | opencode-90d6c4ab41bb097d7db354109e3616ff16778f0b.tar.gz opencode-90d6c4ab41bb097d7db354109e3616ff16778f0b.zip | |
Part data model (#950)
Diffstat (limited to 'packages/tui/sdk')
| -rw-r--r-- | packages/tui/sdk/.stats.yml | 6 | ||||
| -rw-r--r-- | packages/tui/sdk/README.md | 23 | ||||
| -rw-r--r-- | packages/tui/sdk/api.md | 8 | ||||
| -rw-r--r-- | packages/tui/sdk/client_test.go | 44 | ||||
| -rw-r--r-- | packages/tui/sdk/event.go | 8 | ||||
| -rwxr-xr-x | packages/tui/sdk/scripts/lint | 4 | ||||
| -rw-r--r-- | packages/tui/sdk/session.go | 683 | ||||
| -rw-r--r-- | packages/tui/sdk/session_test.go | 18 | ||||
| -rw-r--r-- | packages/tui/sdk/usage_test.go | 7 |
9 files changed, 439 insertions, 362 deletions
diff --git a/packages/tui/sdk/.stats.yml b/packages/tui/sdk/.stats.yml index 4449c4d95..61d2fa3b7 100644 --- a/packages/tui/sdk/.stats.yml +++ b/packages/tui/sdk/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 22 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-eb25bb3673f94d0e98a7036e2a2b0ed7ad63d1598665f2d5e091ec0835273798.yml -openapi_spec_hash: 62f6a8a06aaa4f4ae13e85d56652724f -config_hash: 589ec6a935a43a3c49a325ece86cbda2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-352994eb17f76d9472b0f0176efacf77a200a6fab2db28d1cfcd29451b211d7a.yml +openapi_spec_hash: f01cd3de8c7cf0c9fd513896e81986de +config_hash: 3695cfc829cfaae14490850b4a1ed282 diff --git a/packages/tui/sdk/README.md b/packages/tui/sdk/README.md index 2b5782347..38840b28a 100644 --- a/packages/tui/sdk/README.md +++ b/packages/tui/sdk/README.md @@ -49,11 +49,14 @@ import ( func main() { client := opencode.NewClient() - events, err := client.Event.List(context.TODO()) + stream := client.Event.ListStreaming(context.TODO()) + for stream.Next() { + fmt.Printf("%+v\n", stream.Current()) + } + err := stream.Err() if err != nil { panic(err.Error()) } - fmt.Printf("%+v\n", events) } ``` @@ -171,14 +174,14 @@ When the API returns a non-success status code, we return an error with type To handle errors, we recommend that you use the `errors.As` pattern: ```go -_, err := client.Event.List(context.TODO()) -if err != nil { +stream := client.Event.ListStreaming(context.TODO()) +if stream.Err() != nil { var apierr *opencode.Error - if errors.As(err, &apierr) { + if errors.As(stream.Err(), &apierr) { println(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request println(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response } - panic(err.Error()) // GET "/event": 400 Bad Request { ... } + panic(stream.Err().Error()) // GET "/event": 400 Bad Request { ... } } ``` @@ -196,7 +199,7 @@ To set a per-retry timeout, use `option.WithRequestTimeout()`. // This sets the timeout for the request, including all the retries. ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() -client.Event.List( +client.Event.ListStreaming( ctx, // This sets the per-retry timeout option.WithRequestTimeout(20*time.Second), @@ -231,7 +234,7 @@ client := opencode.NewClient( ) // Override per-request: -client.Event.List(context.TODO(), option.WithMaxRetries(5)) +client.Event.ListStreaming(context.TODO(), option.WithMaxRetries(5)) ``` ### Accessing raw response data (e.g. response headers) @@ -242,8 +245,8 @@ you need to examine response headers, status codes, or other details. ```go // Create a variable to store the HTTP response var response *http.Response -events, err := client.Event.List(context.TODO(), option.WithResponseInto(&response)) -if err != nil { +stream := client.Event.ListStreaming(context.TODO(), option.WithResponseInto(&response)) +if stream.Err() != nil { // handle error } fmt.Printf("%+v\n", events) diff --git a/packages/tui/sdk/api.md b/packages/tui/sdk/api.md index 15bdcfa93..a48e6d7f1 100644 --- a/packages/tui/sdk/api.md +++ b/packages/tui/sdk/api.md @@ -77,15 +77,15 @@ Params Types: - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FilePartParam">FilePartParam</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TextPartParam">TextPartParam</a> -- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessagePartUnionParam">UserMessagePartUnionParam</a> Response Types: - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessage">AssistantMessage</a> -- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessagePart">AssistantMessagePart</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#FilePart">FilePart</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Message">Message</a> +- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Part">Part</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a> +- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#StepFinishPart">StepFinishPart</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#StepStartPart">StepStartPart</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#TextPart">TextPart</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolPart">ToolPart</a> @@ -94,7 +94,7 @@ Response Types: - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStatePending">ToolStatePending</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#ToolStateRunning">ToolStateRunning</a> - <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessage">UserMessage</a> -- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#UserMessagePart">UserMessagePart</a> +- <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a> Methods: @@ -104,7 +104,7 @@ Methods: - <code title="post /session/{id}/abort">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Abort">Abort</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="post /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Chat">Chat</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionChatParams">SessionChatParams</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#AssistantMessage">AssistantMessage</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="post /session/{id}/init">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Init">Init</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionInitParams">SessionInitParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> -- <code title="get /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Message">Message</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> +- <code title="get /session/{id}/message">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Messages">Messages</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) ([]<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionMessagesResponse">SessionMessagesResponse</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="post /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Share">Share</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="post /session/{id}/summarize">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Summarize">Summarize</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>, body <a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionSummarizeParams">SessionSummarizeParams</a>) (<a href="https://pkg.go.dev/builtin#bool">bool</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> - <code title="delete /session/{id}/share">client.Session.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#SessionService.Unshare">Unshare</a>(ctx <a href="https://pkg.go.dev/context">context</a>.<a href="https://pkg.go.dev/context#Context">Context</a>, id <a href="https://pkg.go.dev/builtin#string">string</a>) (<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go">opencode</a>.<a href="https://pkg.go.dev/github.com/sst/opencode-sdk-go#Session">Session</a>, <a href="https://pkg.go.dev/builtin#error">error</a>)</code> diff --git a/packages/tui/sdk/client_test.go b/packages/tui/sdk/client_test.go index e75d64925..62222a465 100644 --- a/packages/tui/sdk/client_test.go +++ b/packages/tui/sdk/client_test.go @@ -38,7 +38,7 @@ func TestUserAgentHeader(t *testing.T) { }, }), ) - client.Event.List(context.Background()) + client.Event.ListStreaming(context.Background()) if userAgent != fmt.Sprintf("Opencode/Go %s", internal.PackageVersion) { t.Errorf("Expected User-Agent to be correct, but got: %#v", userAgent) } @@ -61,7 +61,11 @@ func TestRetryAfter(t *testing.T) { }, }), ) - _, err := client.Event.List(context.Background()) + stream := client.Event.ListStreaming(context.Background()) + for stream.Next() { + // ... + } + err := stream.Err() if err == nil { t.Error("Expected there to be a cancel error") } @@ -95,7 +99,11 @@ func TestDeleteRetryCountHeader(t *testing.T) { }), option.WithHeaderDel("X-Stainless-Retry-Count"), ) - _, err := client.Event.List(context.Background()) + stream := client.Event.ListStreaming(context.Background()) + for stream.Next() { + // ... + } + err := stream.Err() if err == nil { t.Error("Expected there to be a cancel error") } @@ -124,7 +132,11 @@ func TestOverwriteRetryCountHeader(t *testing.T) { }), option.WithHeader("X-Stainless-Retry-Count", "42"), ) - _, err := client.Event.List(context.Background()) + stream := client.Event.ListStreaming(context.Background()) + for stream.Next() { + // ... + } + err := stream.Err() if err == nil { t.Error("Expected there to be a cancel error") } @@ -152,7 +164,11 @@ func TestRetryAfterMs(t *testing.T) { }, }), ) - _, err := client.Event.List(context.Background()) + stream := client.Event.ListStreaming(context.Background()) + for stream.Next() { + // ... + } + err := stream.Err() if err == nil { t.Error("Expected there to be a cancel error") } @@ -174,7 +190,11 @@ func TestContextCancel(t *testing.T) { ) cancelCtx, cancel := context.WithCancel(context.Background()) cancel() - _, err := client.Event.List(cancelCtx) + stream := client.Event.ListStreaming(cancelCtx) + for stream.Next() { + // ... + } + err := stream.Err() if err == nil { t.Error("Expected there to be a cancel error") } @@ -193,7 +213,11 @@ func TestContextCancelDelay(t *testing.T) { ) cancelCtx, cancel := context.WithTimeout(context.Background(), 2*time.Millisecond) defer cancel() - _, err := client.Event.List(cancelCtx) + stream := client.Event.ListStreaming(cancelCtx) + for stream.Next() { + // ... + } + err := stream.Err() if err == nil { t.Error("expected there to be a cancel error") } @@ -218,7 +242,11 @@ func TestContextDeadline(t *testing.T) { }, }), ) - _, err := client.Event.List(deadlineCtx) + stream := client.Event.ListStreaming(deadlineCtx) + for stream.Next() { + // ... + } + err := stream.Err() if err == nil { t.Error("expected there to be a deadline error") } diff --git a/packages/tui/sdk/event.go b/packages/tui/sdk/event.go index 8bbf636c3..9002d2aac 100644 --- a/packages/tui/sdk/event.go +++ b/packages/tui/sdk/event.go @@ -610,18 +610,14 @@ func (r eventListResponseEventMessagePartUpdatedJSON) RawJSON() string { func (r EventListResponseEventMessagePartUpdated) implementsEventListResponse() {} type EventListResponseEventMessagePartUpdatedProperties struct { - MessageID string `json:"messageID,required"` - Part AssistantMessagePart `json:"part,required"` - SessionID string `json:"sessionID,required"` - JSON eventListResponseEventMessagePartUpdatedPropertiesJSON `json:"-"` + Part Part `json:"part,required"` + JSON eventListResponseEventMessagePartUpdatedPropertiesJSON `json:"-"` } // eventListResponseEventMessagePartUpdatedPropertiesJSON contains the JSON // metadata for the struct [EventListResponseEventMessagePartUpdatedProperties] type eventListResponseEventMessagePartUpdatedPropertiesJSON struct { - MessageID apijson.Field Part apijson.Field - SessionID apijson.Field raw string ExtraFields map[string]apijson.Field } diff --git a/packages/tui/sdk/scripts/lint b/packages/tui/sdk/scripts/lint index 9f37abf28..7e03a7beb 100755 --- a/packages/tui/sdk/scripts/lint +++ b/packages/tui/sdk/scripts/lint @@ -5,7 +5,7 @@ set -e cd "$(dirname "$0")/.." echo "==> Running Go build" -go build . +go build ./... echo "==> Checking tests compile" -go test -run=^$ . +go test -run=^$ ./... diff --git a/packages/tui/sdk/session.go b/packages/tui/sdk/session.go index 6321d1ff6..e76ab7f90 100644 --- a/packages/tui/sdk/session.go +++ b/packages/tui/sdk/session.go @@ -101,7 +101,7 @@ func (r *SessionService) Init(ctx context.Context, id string, body SessionInitPa } // List messages for a session -func (r *SessionService) Messages(ctx context.Context, id string, opts ...option.RequestOption) (res *[]Message, err error) { +func (r *SessionService) Messages(ctx context.Context, id string, opts ...option.RequestOption) (res *[]SessionMessagesResponse, err error) { opts = append(r.Options[:], opts...) if id == "" { err = errors.New("missing required id parameter") @@ -152,7 +152,6 @@ type AssistantMessage struct { ID string `json:"id,required"` Cost float64 `json:"cost,required"` ModelID string `json:"modelID,required"` - Parts []AssistantMessagePart `json:"parts,required"` Path AssistantMessagePath `json:"path,required"` ProviderID string `json:"providerID,required"` Role AssistantMessageRole `json:"role,required"` @@ -171,7 +170,6 @@ type assistantMessageJSON struct { ID apijson.Field Cost apijson.Field ModelID apijson.Field - Parts apijson.Field Path apijson.Field ProviderID apijson.Field Role apijson.Field @@ -435,211 +433,23 @@ func (r AssistantMessageErrorName) IsKnown() bool { return false } -type AssistantMessagePart struct { - Type AssistantMessagePartType `json:"type,required"` - ID string `json:"id"` - Cost float64 `json:"cost"` - // This field can have the runtime type of [ToolPartState]. - State interface{} `json:"state"` - Synthetic bool `json:"synthetic"` - Text string `json:"text"` - // This field can have the runtime type of - // [AssistantMessagePartStepFinishPartTokens]. - Tokens interface{} `json:"tokens"` - Tool string `json:"tool"` - JSON assistantMessagePartJSON `json:"-"` - union AssistantMessagePartUnion -} - -// assistantMessagePartJSON contains the JSON metadata for the struct -// [AssistantMessagePart] -type assistantMessagePartJSON struct { - Type apijson.Field - ID apijson.Field - Cost apijson.Field - State apijson.Field - Synthetic apijson.Field - Text apijson.Field - Tokens apijson.Field - Tool apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r assistantMessagePartJSON) RawJSON() string { - return r.raw -} - -func (r *AssistantMessagePart) UnmarshalJSON(data []byte) (err error) { - *r = AssistantMessagePart{} - err = apijson.UnmarshalRoot(data, &r.union) - if err != nil { - return err - } - return apijson.Port(r.union, &r) -} - -// AsUnion returns a [AssistantMessagePartUnion] interface which you can cast to -// the specific types for more type safety. -// -// Possible runtime types of the union are [TextPart], [ToolPart], [StepStartPart], -// [AssistantMessagePartStepFinishPart]. -func (r AssistantMessagePart) AsUnion() AssistantMessagePartUnion { - return r.union -} - -// Union satisfied by [TextPart], [ToolPart], [StepStartPart] or -// [AssistantMessagePartStepFinishPart]. -type AssistantMessagePartUnion interface { - implementsAssistantMessagePart() -} - -func init() { - apijson.RegisterUnion( - reflect.TypeOf((*AssistantMessagePartUnion)(nil)).Elem(), - "type", - apijson.UnionVariant{ - TypeFilter: gjson.JSON, - Type: reflect.TypeOf(TextPart{}), - DiscriminatorValue: "text", - }, - apijson.UnionVariant{ - TypeFilter: gjson.JSON, - Type: reflect.TypeOf(ToolPart{}), - DiscriminatorValue: "tool", - }, - apijson.UnionVariant{ - TypeFilter: gjson.JSON, - Type: reflect.TypeOf(StepStartPart{}), - DiscriminatorValue: "step-start", - }, - apijson.UnionVariant{ - TypeFilter: gjson.JSON, - Type: reflect.TypeOf(AssistantMessagePartStepFinishPart{}), - DiscriminatorValue: "step-finish", - }, - ) -} - -type AssistantMessagePartStepFinishPart struct { - Cost float64 `json:"cost,required"` - Tokens AssistantMessagePartStepFinishPartTokens `json:"tokens,required"` - Type AssistantMessagePartStepFinishPartType `json:"type,required"` - JSON assistantMessagePartStepFinishPartJSON `json:"-"` -} - -// assistantMessagePartStepFinishPartJSON contains the JSON metadata for the struct -// [AssistantMessagePartStepFinishPart] -type assistantMessagePartStepFinishPartJSON struct { - Cost apijson.Field - Tokens apijson.Field - Type apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *AssistantMessagePartStepFinishPart) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r assistantMessagePartStepFinishPartJSON) RawJSON() string { - return r.raw -} - -func (r AssistantMessagePartStepFinishPart) implementsAssistantMessagePart() {} - -type AssistantMessagePartStepFinishPartTokens struct { - Cache AssistantMessagePartStepFinishPartTokensCache `json:"cache,required"` - Input float64 `json:"input,required"` - Output float64 `json:"output,required"` - Reasoning float64 `json:"reasoning,required"` - JSON assistantMessagePartStepFinishPartTokensJSON `json:"-"` -} - -// assistantMessagePartStepFinishPartTokensJSON contains the JSON metadata for the -// struct [AssistantMessagePartStepFinishPartTokens] -type assistantMessagePartStepFinishPartTokensJSON struct { - Cache apijson.Field - Input apijson.Field - Output apijson.Field - Reasoning apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *AssistantMessagePartStepFinishPartTokens) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r assistantMessagePartStepFinishPartTokensJSON) RawJSON() string { - return r.raw -} - -type AssistantMessagePartStepFinishPartTokensCache struct { - Read float64 `json:"read,required"` - Write float64 `json:"write,required"` - JSON assistantMessagePartStepFinishPartTokensCacheJSON `json:"-"` -} - -// assistantMessagePartStepFinishPartTokensCacheJSON contains the JSON metadata for -// the struct [AssistantMessagePartStepFinishPartTokensCache] -type assistantMessagePartStepFinishPartTokensCacheJSON struct { - Read apijson.Field - Write apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *AssistantMessagePartStepFinishPartTokensCache) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r assistantMessagePartStepFinishPartTokensCacheJSON) RawJSON() string { - return r.raw -} - -type AssistantMessagePartStepFinishPartType string - -const ( - AssistantMessagePartStepFinishPartTypeStepFinish AssistantMessagePartStepFinishPartType = "step-finish" -) - -func (r AssistantMessagePartStepFinishPartType) IsKnown() bool { - switch r { - case AssistantMessagePartStepFinishPartTypeStepFinish: - return true - } - return false -} - -type AssistantMessagePartType string - -const ( - AssistantMessagePartTypeText AssistantMessagePartType = "text" - AssistantMessagePartTypeTool AssistantMessagePartType = "tool" - AssistantMessagePartTypeStepStart AssistantMessagePartType = "step-start" - AssistantMessagePartTypeStepFinish AssistantMessagePartType = "step-finish" -) - -func (r AssistantMessagePartType) IsKnown() bool { - switch r { - case AssistantMessagePartTypeText, AssistantMessagePartTypeTool, AssistantMessagePartTypeStepStart, AssistantMessagePartTypeStepFinish: - return true - } - return false -} - type FilePart struct { - Mime string `json:"mime,required"` - Type FilePartType `json:"type,required"` - URL string `json:"url,required"` - Filename string `json:"filename"` - JSON filePartJSON `json:"-"` + ID string `json:"id,required"` + MessageID string `json:"messageID,required"` + Mime string `json:"mime,required"` + SessionID string `json:"sessionID,required"` + Type FilePartType `json:"type,required"` + URL string `json:"url,required"` + Filename string `json:"filename"` + JSON filePartJSON `json:"-"` } // filePartJSON contains the JSON metadata for the struct [FilePart] type filePartJSON struct { + ID apijson.Field + MessageID apijson.Field Mime apijson.Field + SessionID apijson.Field Type apijson.Field URL apijson.Field Filename apijson.Field @@ -655,7 +465,7 @@ func (r filePartJSON) RawJSON() string { return r.raw } -func (r FilePart) implementsUserMessagePart() {} +func (r FilePart) implementsPart() {} type FilePartType string @@ -672,23 +482,23 @@ func (r FilePartType) IsKnown() bool { } type FilePartParam struct { - Mime param.Field[string] `json:"mime,required"` - Type param.Field[FilePartType] `json:"type,required"` - URL param.Field[string] `json:"url,required"` - Filename param.Field[string] `json:"filename"` + ID param.Field[string] `json:"id,required"` + MessageID param.Field[string] `json:"messageID,required"` + Mime param.Field[string] `json:"mime,required"` + SessionID param.Field[string] `json:"sessionID,required"` + Type param.Field[FilePartType] `json:"type,required"` + URL param.Field[string] `json:"url,required"` + Filename param.Field[string] `json:"filename"` } func (r FilePartParam) MarshalJSON() (data []byte, err error) { return apijson.MarshalRoot(r) } -func (r FilePartParam) implementsUserMessagePartUnionParam() {} +func (r FilePartParam) implementsSessionChatParamsPartUnion() {} type Message struct { - ID string `json:"id,required"` - // This field can have the runtime type of [[]UserMessagePart], - // [[]AssistantMessagePart]. - Parts interface{} `json:"parts,required"` + ID string `json:"id,required"` Role MessageRole `json:"role,required"` SessionID string `json:"sessionID,required"` // This field can have the runtime type of [UserMessageTime], @@ -713,7 +523,6 @@ type Message struct { // messageJSON contains the JSON metadata for the struct [Message] type messageJSON struct { ID apijson.Field - Parts apijson.Field Role apijson.Field SessionID apijson.Field Time apijson.Field @@ -787,6 +596,128 @@ func (r MessageRole) IsKnown() bool { return false } +type Part struct { + ID string `json:"id,required"` + MessageID string `json:"messageID,required"` + SessionID string `json:"sessionID,required"` + Type PartType `json:"type,required"` + CallID string `json:"callID"` + Cost float64 `json:"cost"` + Filename string `json:"filename"` + Mime string `json:"mime"` + // This field can have the runtime type of [ToolPartState]. + State interface{} `json:"state"` + Synthetic bool `json:"synthetic"` + Text string `json:"text"` + // This field can have the runtime type of [TextPartTime]. + Time interface{} `json:"time"` + // This field can have the runtime type of [StepFinishPartTokens]. + Tokens interface{} `json:"tokens"` + Tool string `json:"tool"` + URL string `json:"url"` + JSON partJSON `json:"-"` + union PartUnion +} + +// partJSON contains the JSON metadata for the struct [Part] +type partJSON struct { + ID apijson.Field + MessageID apijson.Field + SessionID apijson.Field + Type apijson.Field + CallID apijson.Field + Cost apijson.Field + Filename apijson.Field + Mime apijson.Field + State apijson.Field + Synthetic apijson.Field + Text apijson.Field + Time apijson.Field + Tokens apijson.Field + Tool apijson.Field + URL apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r partJSON) RawJSON() string { + return r.raw +} + +func (r *Part) UnmarshalJSON(data []byte) (err error) { + *r = Part{} + err = apijson.UnmarshalRoot(data, &r.union) + if err != nil { + return err + } + return apijson.Port(r.union, &r) +} + +// AsUnion returns a [PartUnion] interface which you can cast to the specific types +// for more type safety. +// +// Possible runtime types of the union are [TextPart], [FilePart], [ToolPart], +// [StepStartPart], [StepFinishPart]. +func (r Part) AsUnion() PartUnion { + return r.union +} + +// Union satisfied by [TextPart], [FilePart], [ToolPart], [StepStartPart] or +// [StepFinishPart]. +type PartUnion interface { + implementsPart() +} + +func init() { + apijson.RegisterUnion( + reflect.TypeOf((*PartUnion)(nil)).Elem(), + "type", + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(TextPart{}), + DiscriminatorValue: "text", + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(FilePart{}), + DiscriminatorValue: "file", + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(ToolPart{}), + DiscriminatorValue: "tool", + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(StepStartPart{}), + DiscriminatorValue: "step-start", + }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(StepFinishPart{}), + DiscriminatorValue: "step-finish", + }, + ) +} + +type PartType string + +const ( + PartTypeText PartType = "text" + PartTypeFile PartType = "file" + PartTypeTool PartType = "tool" + PartTypeStepStart PartType = "step-start" + PartTypeStepFinish PartType = "step-finish" +) + +func (r PartType) IsKnown() bool { + switch r { + case PartTypeText, PartTypeFile, PartTypeTool, PartTypeStepStart, PartTypeStepFinish: + return true + } + return false +} + type Session struct { ID string `json:"id,required"` Time SessionTime `json:"time,required"` @@ -885,13 +816,115 @@ func (r sessionShareJSON) RawJSON() string { return r.raw } +type StepFinishPart struct { + ID string `json:"id,required"` + Cost float64 `json:"cost,required"` + MessageID string `json:"messageID,required"` + SessionID string `json:"sessionID,required"` + Tokens StepFinishPartTokens `json:"tokens,required"` + Type StepFinishPartType `json:"type,required"` + JSON stepFinishPartJSON `json:"-"` +} + +// stepFinishPartJSON contains the JSON metadata for the struct [StepFinishPart] +type stepFinishPartJSON struct { + ID apijson.Field + Cost apijson.Field + MessageID apijson.Field + SessionID apijson.Field + Tokens apijson.Field + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *StepFinishPart) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r stepFinishPartJSON) RawJSON() string { + return r.raw +} + +func (r StepFinishPart) implementsPart() {} + +type StepFinishPartTokens struct { + Cache StepFinishPartTokensCache `json:"cache,required"` + Input float64 `json:"input,required"` + Output float64 `json:"output,required"` + Reasoning float64 `json:"reasoning,required"` + JSON stepFinishPartTokensJSON `json:"-"` +} + +// stepFinishPartTokensJSON contains the JSON metadata for the struct +// [StepFinishPartTokens] +type stepFinishPartTokensJSON struct { + Cache apijson.Field + Input apijson.Field + Output apijson.Field + Reasoning apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *StepFinishPartTokens) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r stepFinishPartTokensJSON) RawJSON() string { + return r.raw +} + +type StepFinishPartTokensCache struct { + Read float64 `json:"read,required"` + Write float64 `json:"write,required"` + JSON stepFinishPartTokensCacheJSON `json:"-"` +} + +// stepFinishPartTokensCacheJSON contains the JSON metadata for the struct +// [StepFinishPartTokensCache] +type stepFinishPartTokensCacheJSON struct { + Read apijson.Field + Write apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *StepFinishPartTokensCache) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r stepFinishPartTokensCacheJSON) RawJSON() string { + return r.raw +} + +type StepFinishPartType string + +const ( + StepFinishPartTypeStepFinish StepFinishPartType = "step-finish" +) + +func (r StepFinishPartType) IsKnown() bool { + switch r { + case StepFinishPartTypeStepFinish: + return true + } + return false +} + type StepStartPart struct { - Type StepStartPartType `json:"type,required"` - JSON stepStartPartJSON `json:"-"` + ID string `json:"id,required"` + MessageID string `json:"messageID,required"` + SessionID string `json:"sessionID,required"` + Type StepStartPartType `json:"type,required"` + JSON stepStartPartJSON `json:"-"` } // stepStartPartJSON contains the JSON metadata for the struct [StepStartPart] type stepStartPartJSON struct { + ID apijson.Field + MessageID apijson.Field + SessionID apijson.Field Type apijson.Field raw string ExtraFields map[string]apijson.Field @@ -905,7 +938,7 @@ func (r stepStartPartJSON) RawJSON() string { return r.raw } -func (r StepStartPart) implementsAssistantMessagePart() {} +func (r StepStartPart) implementsPart() {} type StepStartPartType string @@ -922,17 +955,25 @@ func (r StepStartPartType) IsKnown() bool { } type TextPart struct { + ID string `json:"id,required"` + MessageID string `json:"messageID,required"` + SessionID string `json:"sessionID,required"` Text string `json:"text,required"` Type TextPartType `json:"type,required"` Synthetic bool `json:"synthetic"` + Time TextPartTime `json:"time"` JSON textPartJSON `json:"-"` } // textPartJSON contains the JSON metadata for the struct [TextPart] type textPartJSON struct { + ID apijson.Field + MessageID apijson.Field + SessionID apijson.Field Text apijson.Field Type apijson.Field Synthetic apijson.Field + Time apijson.Field raw string ExtraFields map[string]apijson.Field } @@ -945,9 +986,7 @@ func (r textPartJSON) RawJSON() string { return r.raw } -func (r TextPart) implementsAssistantMessagePart() {} - -func (r TextPart) implementsUserMessagePart() {} +func (r TextPart) implementsPart() {} type TextPartType string @@ -963,29 +1002,70 @@ func (r TextPartType) IsKnown() bool { return false } +type TextPartTime struct { + Start float64 `json:"start,required"` + End float64 `json:"end"` + JSON textPartTimeJSON `json:"-"` +} + +// textPartTimeJSON contains the JSON metadata for the struct [TextPartTime] +type textPartTimeJSON struct { + Start apijson.Field + End apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *TextPartTime) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r textPartTimeJSON) RawJSON() string { + return r.raw +} + type TextPartParam struct { - Text param.Field[string] `json:"text,required"` - Type param.Field[TextPartType] `json:"type,required"` - Synthetic param.Field[bool] `json:"synthetic"` + ID param.Field[string] `json:"id,required"` + MessageID param.Field[string] `json:"messageID,required"` + SessionID param.Field[string] `json:"sessionID,required"` + Text param.Field[string] `json:"text,required"` + Type param.Field[TextPartType] `json:"type,required"` + Synthetic param.Field[bool] `json:"synthetic"` + Time param.Field[TextPartTimeParam] `json:"time"` } func (r TextPartParam) MarshalJSON() (data []byte, err error) { return apijson.MarshalRoot(r) } -func (r TextPartParam) implementsUserMessagePartUnionParam() {} +func (r TextPartParam) implementsSessionChatParamsPartUnion() {} + +type TextPartTimeParam struct { + Start param.Field[float64] `json:"start,required"` + End param.Field[float64] `json:"end"` +} + +func (r TextPartTimeParam) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) +} type ToolPart struct { - ID string `json:"id,required"` - State ToolPartState `json:"state,required"` - Tool string `json:"tool,required"` - Type ToolPartType `json:"type,required"` - JSON toolPartJSON `json:"-"` + ID string `json:"id,required"` + CallID string `json:"callID,required"` + MessageID string `json:"messageID,required"` + SessionID string `json:"sessionID,required"` + State ToolPartState `json:"state,required"` + Tool string `json:"tool,required"` + Type ToolPartType `json:"type,required"` + JSON toolPartJSON `json:"-"` } // toolPartJSON contains the JSON metadata for the struct [ToolPart] type toolPartJSON struct { ID apijson.Field + CallID apijson.Field + MessageID apijson.Field + SessionID apijson.Field State apijson.Field Tool apijson.Field Type apijson.Field @@ -1001,7 +1081,7 @@ func (r toolPartJSON) RawJSON() string { return r.raw } -func (r ToolPart) implementsAssistantMessagePart() {} +func (r ToolPart) implementsPart() {} type ToolPartState struct { Status ToolPartStateStatus `json:"status,required"` @@ -1357,18 +1437,16 @@ func (r toolStateRunningTimeJSON) RawJSON() string { } type UserMessage struct { - ID string `json:"id,required"` - Parts []UserMessagePart `json:"parts,required"` - Role UserMessageRole `json:"role,required"` - SessionID string `json:"sessionID,required"` - Time UserMessageTime `json:"time,required"` - JSON userMessageJSON `json:"-"` + ID string `json:"id,required"` + Role UserMessageRole `json:"role,required"` + SessionID string `json:"sessionID,required"` + Time UserMessageTime `json:"time,required"` + JSON userMessageJSON `json:"-"` } // userMessageJSON contains the JSON metadata for the struct [UserMessage] type userMessageJSON struct { ID apijson.Field - Parts apijson.Field Role apijson.Field SessionID apijson.Field Time apijson.Field @@ -1420,119 +1498,82 @@ func (r userMessageTimeJSON) RawJSON() string { return r.raw } -type UserMessagePart struct { - Type UserMessagePartType `json:"type,required"` - Filename string `json:"filename"` - Mime string `json:"mime"` - Synthetic bool `json:"synthetic"` - Text string `json:"text"` - URL string `json:"url"` - JSON userMessagePartJSON `json:"-"` - union UserMessagePartUnion +type SessionMessagesResponse struct { + Info Message `json:"info,required"` + Parts []Part `json:"parts,required"` + JSON sessionMessagesResponseJSON `json:"-"` } -// userMessagePartJSON contains the JSON metadata for the struct [UserMessagePart] -type userMessagePartJSON struct { - Type apijson.Field - Filename apijson.Field - Mime apijson.Field - Synthetic apijson.Field - Text apijson.Field - URL apijson.Field +// sessionMessagesResponseJSON contains the JSON metadata for the struct +// [SessionMessagesResponse] +type sessionMessagesResponseJSON struct { + Info apijson.Field + Parts apijson.Field raw string ExtraFields map[string]apijson.Field } -func (r userMessagePartJSON) RawJSON() string { +func (r *SessionMessagesResponse) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r sessionMessagesResponseJSON) RawJSON() string { return r.raw } -func (r *UserMessagePart) UnmarshalJSON(data []byte) (err error) { - *r = UserMessagePart{} - err = apijson.UnmarshalRoot(data, &r.union) - if err != nil { - return err - } - return apijson.Port(r.union, &r) +type SessionChatParams struct { + MessageID param.Field[string] `json:"messageID,required"` + Mode param.Field[string] `json:"mode,required"` + ModelID param.Field[string] `json:"modelID,required"` + Parts param.Field[[]SessionChatParamsPartUnion] `json:"parts,required"` + ProviderID param.Field[string] `json:"providerID,required"` } -// AsUnion returns a [UserMessagePartUnion] interface which you can cast to the -// specific types for more type safety. -// -// Possible runtime types of the union are [TextPart], [FilePart]. -func (r UserMessagePart) AsUnion() UserMessagePartUnion { - return r.union +func (r SessionChatParams) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) } -// Union satisfied by [TextPart] or [FilePart]. -type UserMessagePartUnion interface { - implementsUserMessagePart() +type SessionChatParamsPart struct { + ID param.Field[string] `json:"id,required"` + MessageID param.Field[string] `json:"messageID,required"` + SessionID param.Field[string] `json:"sessionID,required"` + Type param.Field[SessionChatParamsPartsType] `json:"type,required"` + Filename param.Field[string] `json:"filename"` + Mime param.Field[string] `json:"mime"` + Synthetic param.Field[bool] `json:"synthetic"` + Text param.Field[string] `json:"text"` + Time param.Field[interface{}] `json:"time"` + URL param.Field[string] `json:"url"` } -func init() { - apijson.RegisterUnion( - reflect.TypeOf((*UserMessagePartUnion)(nil)).Elem(), - "type", - apijson.UnionVariant{ - TypeFilter: gjson.JSON, - Type: reflect.TypeOf(TextPart{}), - DiscriminatorValue: "text", - }, - apijson.UnionVariant{ - TypeFilter: gjson.JSON, - Type: reflect.TypeOf(FilePart{}), - DiscriminatorValue: "file", - }, - ) +func (r SessionChatParamsPart) MarshalJSON() (data []byte, err error) { + return apijson.MarshalRoot(r) } -type UserMessagePartType string +func (r SessionChatParamsPart) implementsSessionChatParamsPartUnion() {} + +// Satisfied by [FilePartParam], [TextPartParam], [SessionChatParamsPart]. +type SessionChatParamsPartUnion interface { + implementsSessionChatParamsPartUnion() +} + +type SessionChatParamsPartsType string const ( - UserMessagePartTypeText UserMessagePartType = "text" - UserMessagePartTypeFile UserMessagePartType = "file" + SessionChatParamsPartsTypeFile SessionChatParamsPartsType = "file" + SessionChatParamsPartsTypeText SessionChatParamsPartsType = "text" ) -func (r UserMessagePartType) IsKnown() bool { +func (r SessionChatParamsPartsType) IsKnown() bool { switch r { - case UserMessagePartTypeText, UserMessagePartTypeFile: + case SessionChatParamsPartsTypeFile, SessionChatParamsPartsTypeText: return true } return false } -type UserMessagePartParam struct { - Type param.Field[UserMessagePartType] `json:"type,required"` - Filename param.Field[string] `json:"filename"` - Mime param.Field[string] `json:"mime"` - Synthetic param.Field[bool] `json:"synthetic"` - Text param.Field[string] `json:"text"` - URL param.Field[string] `json:"url"` -} - -func (r UserMessagePartParam) MarshalJSON() (data []byte, err error) { - return apijson.MarshalRoot(r) -} - -func (r UserMessagePartParam) implementsUserMessagePartUnionParam() {} - -// Satisfied by [TextPartParam], [FilePartParam], [UserMessagePartParam]. -type UserMessagePartUnionParam interface { - implementsUserMessagePartUnionParam() -} - -type SessionChatParams struct { - Mode param.Field[string] `json:"mode,required"` - ModelID param.Field[string] `json:"modelID,required"` - Parts param.Field[[]UserMessagePartUnionParam] `json:"parts,required"` - ProviderID param.Field[string] `json:"providerID,required"` -} - -func (r SessionChatParams) MarshalJSON() (data []byte, err error) { - return apijson.MarshalRoot(r) -} - type SessionInitParams struct { + MessageID param.Field[string] `json:"messageID,required"` ModelID param.Field[string] `json:"modelID,required"` ProviderID param.Field[string] `json:"providerID,required"` } diff --git a/packages/tui/sdk/session_test.go b/packages/tui/sdk/session_test.go index 4ff2818c5..c74a4a385 100644 --- a/packages/tui/sdk/session_test.go +++ b/packages/tui/sdk/session_test.go @@ -117,12 +117,17 @@ func TestSessionChat(t *testing.T) { context.TODO(), "id", opencode.SessionChatParams{ - Mode: opencode.F("mode"), - ModelID: opencode.F("modelID"), - Parts: opencode.F([]opencode.UserMessagePartUnionParam{opencode.TextPartParam{ - Text: opencode.F("text"), - Type: opencode.F(opencode.TextPartTypeText), - Synthetic: opencode.F(true), + MessageID: opencode.F("messageID"), + Mode: opencode.F("mode"), + ModelID: opencode.F("modelID"), + Parts: opencode.F([]opencode.SessionChatParamsPartUnion{opencode.FilePartParam{ + ID: opencode.F("id"), + MessageID: opencode.F("messageID"), + Mime: opencode.F("mime"), + SessionID: opencode.F("sessionID"), + Type: opencode.F(opencode.FilePartTypeFile), + URL: opencode.F("url"), + Filename: opencode.F("filename"), }}), ProviderID: opencode.F("providerID"), }, @@ -152,6 +157,7 @@ func TestSessionInit(t *testing.T) { context.TODO(), "id", opencode.SessionInitParams{ + MessageID: opencode.F("messageID"), ModelID: opencode.F("modelID"), ProviderID: opencode.F("providerID"), }, diff --git a/packages/tui/sdk/usage_test.go b/packages/tui/sdk/usage_test.go index 0e261a7aa..5e8f44c7c 100644 --- a/packages/tui/sdk/usage_test.go +++ b/packages/tui/sdk/usage_test.go @@ -23,10 +23,13 @@ func TestUsage(t *testing.T) { client := opencode.NewClient( option.WithBaseURL(baseURL), ) - events, err := client.Event.List(context.TODO()) + stream := client.Event.ListStreaming(context.TODO()) + for stream.Next() { + t.Logf("%+v\n", stream.Current()) + } + err := stream.Err() if err != nil { t.Error(err) return } - t.Logf("%+v\n", events) } |
