diff --git a/packages/opencode/src/provider/transform.ts b/packages/opencode/src/provider/transform.ts index 804434f8..3c607884 100644 --- a/packages/opencode/src/provider/transform.ts +++ b/packages/opencode/src/provider/transform.ts @@ -1,9 +1,9 @@ -import type { LanguageModelV1Prompt } from "ai" +import type { ModelMessage } from "ai" import { unique } from "remeda" export namespace ProviderTransform { export function message( - msgs: LanguageModelV1Prompt, + msgs: ModelMessage[], providerID: string, modelID: string, ) { @@ -12,8 +12,8 @@ export namespace ProviderTransform { const final = msgs.filter((msg) => msg.role !== "system").slice(-2) for (const msg of unique([...system, ...final])) { - msg.providerMetadata = { - ...msg.providerMetadata, + msg.providerOptions = { + ...msg.providerOptions, anthropic: { cacheControl: { type: "ephemeral" }, }, @@ -28,8 +28,8 @@ export namespace ProviderTransform { const final = msgs.filter((msg) => msg.role !== "system").slice(-2) for (const msg of unique([...system, ...final])) { - msg.providerMetadata = { - ...msg.providerMetadata, + msg.providerOptions = { + ...msg.providerOptions, bedrock: { cachePoint: { type: "ephemeral" }, }, diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index b1788dde..11686462 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -494,24 +494,23 @@ export namespace Session { description: item.description, inputSchema: item.parameters as ZodSchema, async execute(args, opts) { - const start = Date.now() - try { - const result = await item.execute(args, { - sessionID: input.sessionID, - abort: abort.signal, - messageID: next.id, - metadata: async (val) => { - const match = next.parts.find( - (p): p is MessageV2.ToolPart => - p.type === "tool" && p.id === opts.toolCallId, - ) - await updateMessage(next) - }, - }) - return result - } catch (e: any) { - return e.toString() - } + const result = await item.execute(args, { + sessionID: input.sessionID, + abort: abort.signal, + messageID: next.id, + metadata: async (val) => { + const match = next.parts.find( + (p): p is MessageV2.ToolPart => + p.type === "tool" && p.id === opts.toolCallId, + ) + if (match && match.state.status === "running") { + match.state.title = val.title + match.state.metadata = val.metadata + } + await updateMessage(next) + }, + }) + return result }, toModelOutput(result) { return { @@ -526,7 +525,6 @@ export namespace Session { const execute = item.execute if (!execute) continue item.execute = async (args, opts) => { - const start = Date.now() try { const result = await execute(args, opts) return result.content @@ -612,6 +610,9 @@ export namespace Session { }) break + case "tool-input-delta": + break + case "tool-call": { const match = next.parts.find( (p): p is MessageV2.ToolPart => @@ -659,6 +660,30 @@ export namespace Session { break } + case "tool-error": { + const match = next.parts.find( + (p): p is MessageV2.ToolPart => + p.type === "tool" && p.id === value.toolCallId, + ) + if (match && match.state.status === "running") { + match.state = { + status: "error", + input: value.input, + error: (value.error as any).toString(), + time: { + start: match.state.time.start, + end: Date.now(), + }, + } + Bus.publish(MessageV2.Event.PartUpdated, { + part: match, + sessionID: next.sessionID, + messageID: next.id, + }) + } + break + } + case "error": const e = value.error log.error("", { diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts index d7b76cc0..e9263c06 100644 --- a/packages/opencode/src/session/message-v2.ts +++ b/packages/opencode/src/session/message-v2.ts @@ -25,6 +25,8 @@ export namespace MessageV2 { .object({ status: z.literal("running"), input: z.any(), + title: z.string().optional(), + metadata: z.record(z.any()).optional(), time: z.object({ start: z.number(), }), @@ -33,7 +35,7 @@ export namespace MessageV2 { ref: "ToolStateRunning", }) - export const ToolInvocationCompleted = z + export const ToolStateCompleted = z .object({ status: z.literal("completed"), input: z.any(), @@ -46,14 +48,29 @@ export namespace MessageV2 { }), }) .openapi({ - ref: "ToolInvocationCompleted", + ref: "ToolStateCompleted", + }) + + export const ToolStateError = z + .object({ + status: z.literal("error"), + input: z.any(), + error: z.string(), + time: z.object({ + start: z.number(), + end: z.number(), + }), + }) + .openapi({ + ref: "ToolStateError", }) export const ToolState = z .discriminatedUnion("status", [ ToolStatePending, ToolStateRunning, - ToolInvocationCompleted, + ToolStateCompleted, + ToolStateError, ]) .openapi({ ref: "ToolState", @@ -348,7 +365,7 @@ export namespace MessageV2 { text: part.text, }, ] - if (part.type === "tool") + if (part.type === "tool") { if (part.state.status === "completed") return [ { @@ -367,6 +384,25 @@ export namespace MessageV2 { }, }, ] + if (part.state.status === "error") + return [ + { + type: "tool-call", + input: part.state.input, + toolName: part.tool, + toolCallId: part.id, + }, + { + type: "tool-result", + toolCallId: part.id, + toolName: part.tool, + output: { + type: "text", + value: part.state.error, + }, + }, + ] + } return [] }, diff --git a/packages/tui/go.mod b/packages/tui/go.mod index 74047af1..f7091f9d 100644 --- a/packages/tui/go.mod +++ b/packages/tui/go.mod @@ -15,7 +15,7 @@ require ( github.com/muesli/reflow v0.3.0 github.com/muesli/termenv v0.16.0 github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 - github.com/sst/opencode-sdk-go v0.1.0-alpha.8 + github.com/stainless-sdks/opencode-go dev github.com/tidwall/gjson v1.14.4 rsc.io/qr v0.2.0 ) diff --git a/packages/tui/sdk/.stats.yml b/packages/tui/sdk/.stats.yml index 3038116a..1eef7bb5 100644 --- a/packages/tui/sdk/.stats.yml +++ b/packages/tui/sdk/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 20 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-9dcfe3e5f2d5eef1bcbf70cb6bd38e71802f1197468d49b03d4148e741726553.yml -openapi_spec_hash: 65be139c91c4241a665b458cbfb08f8e -config_hash: 61d6c861cb32b16df2ba4a4973c339ee +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-15eeb028f79b9a065b4e54a6ea6a58631e9bd5004f97820f0c79d18e3f8bac84.yml +openapi_spec_hash: 38c8bacb6c8e4c46852a3e81e3fb9fda +config_hash: 348a85e725de595ca05a61f4333794ac diff --git a/packages/tui/sdk/api.md b/packages/tui/sdk/api.md index fb4afbf9..c9859d19 100644 --- a/packages/tui/sdk/api.md +++ b/packages/tui/sdk/api.md @@ -72,15 +72,23 @@ Params Types: - opencode.FilePartParam - opencode.TextPartParam +- opencode.UserMessagePartUnionParam Response Types: - opencode.AssistantMessage +- opencode.AssistantMessagePart - opencode.FilePart - opencode.Message - opencode.Session +- opencode.StepStartPart - opencode.TextPart - opencode.ToolPart +- opencode.ToolStateCompleted +- opencode.ToolStateError +- opencode.ToolStatePending +- opencode.ToolStateRunning +- opencode.UserMessagePart Methods: diff --git a/packages/tui/sdk/event.go b/packages/tui/sdk/event.go index b793774a..48eb129f 100644 --- a/packages/tui/sdk/event.go +++ b/packages/tui/sdk/event.go @@ -673,7 +673,7 @@ func (r EventListResponseEventMessagePartUpdated) implementsEventListResponse() type EventListResponseEventMessagePartUpdatedProperties struct { MessageID string `json:"messageID,required"` - Part EventListResponseEventMessagePartUpdatedPropertiesPart `json:"part,required"` + Part AssistantMessagePart `json:"part,required"` SessionID string `json:"sessionID,required"` JSON eventListResponseEventMessagePartUpdatedPropertiesJSON `json:"-"` } @@ -696,134 +696,6 @@ func (r eventListResponseEventMessagePartUpdatedPropertiesJSON) RawJSON() string return r.raw } -type EventListResponseEventMessagePartUpdatedPropertiesPart struct { - Type EventListResponseEventMessagePartUpdatedPropertiesPartType `json:"type,required"` - ID string `json:"id"` - // This field can have the runtime type of [ToolPartState]. - State interface{} `json:"state"` - Text string `json:"text"` - Tool string `json:"tool"` - JSON eventListResponseEventMessagePartUpdatedPropertiesPartJSON `json:"-"` - union EventListResponseEventMessagePartUpdatedPropertiesPartUnion -} - -// eventListResponseEventMessagePartUpdatedPropertiesPartJSON contains the JSON -// metadata for the struct [EventListResponseEventMessagePartUpdatedPropertiesPart] -type eventListResponseEventMessagePartUpdatedPropertiesPartJSON struct { - Type apijson.Field - ID apijson.Field - State apijson.Field - Text apijson.Field - Tool apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r eventListResponseEventMessagePartUpdatedPropertiesPartJSON) RawJSON() string { - return r.raw -} - -func (r *EventListResponseEventMessagePartUpdatedPropertiesPart) UnmarshalJSON(data []byte) (err error) { - *r = EventListResponseEventMessagePartUpdatedPropertiesPart{} - err = apijson.UnmarshalRoot(data, &r.union) - if err != nil { - return err - } - return apijson.Port(r.union, &r) -} - -// AsUnion returns a [EventListResponseEventMessagePartUpdatedPropertiesPartUnion] -// interface which you can cast to the specific types for more type safety. -// -// Possible runtime types of the union are [TextPart], [ToolPart], -// [EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPart]. -func (r EventListResponseEventMessagePartUpdatedPropertiesPart) AsUnion() EventListResponseEventMessagePartUpdatedPropertiesPartUnion { - return r.union -} - -// Union satisfied by [TextPart], [ToolPart] or -// [EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPart]. -type EventListResponseEventMessagePartUpdatedPropertiesPartUnion interface { - implementsEventListResponseEventMessagePartUpdatedPropertiesPart() -} - -func init() { - apijson.RegisterUnion( - reflect.TypeOf((*EventListResponseEventMessagePartUpdatedPropertiesPartUnion)(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(EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPart{}), - DiscriminatorValue: "step-start", - }, - ) -} - -type EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPart struct { - Type EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartType `json:"type,required"` - JSON eventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartJSON `json:"-"` -} - -// eventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartJSON contains -// the JSON metadata for the struct -// [EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPart] -type eventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartJSON struct { - Type apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPart) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r eventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartJSON) RawJSON() string { - return r.raw -} - -func (r EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPart) implementsEventListResponseEventMessagePartUpdatedPropertiesPart() { -} - -type EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartType string - -const ( - EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartTypeStepStart EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartType = "step-start" -) - -func (r EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartType) IsKnown() bool { - switch r { - case EventListResponseEventMessagePartUpdatedPropertiesPartStepStartPartTypeStepStart: - return true - } - return false -} - -type EventListResponseEventMessagePartUpdatedPropertiesPartType string - -const ( - EventListResponseEventMessagePartUpdatedPropertiesPartTypeText EventListResponseEventMessagePartUpdatedPropertiesPartType = "text" - EventListResponseEventMessagePartUpdatedPropertiesPartTypeTool EventListResponseEventMessagePartUpdatedPropertiesPartType = "tool" - EventListResponseEventMessagePartUpdatedPropertiesPartTypeStepStart EventListResponseEventMessagePartUpdatedPropertiesPartType = "step-start" -) - -func (r EventListResponseEventMessagePartUpdatedPropertiesPartType) IsKnown() bool { - switch r { - case EventListResponseEventMessagePartUpdatedPropertiesPartTypeText, EventListResponseEventMessagePartUpdatedPropertiesPartTypeTool, EventListResponseEventMessagePartUpdatedPropertiesPartTypeStepStart: - return true - } - return false -} - type EventListResponseEventMessagePartUpdatedType string const ( diff --git a/packages/tui/sdk/session.go b/packages/tui/sdk/session.go index 7af802ab..8e0a9b39 100644 --- a/packages/tui/sdk/session.go +++ b/packages/tui/sdk/session.go @@ -195,132 +195,6 @@ func (r assistantMessageJSON) RawJSON() string { func (r AssistantMessage) implementsMessage() {} -type AssistantMessagePart struct { - Type AssistantMessagePartsType `json:"type,required"` - ID string `json:"id"` - // This field can have the runtime type of [ToolPartState]. - State interface{} `json:"state"` - Text string `json:"text"` - Tool string `json:"tool"` - JSON assistantMessagePartJSON `json:"-"` - union AssistantMessagePartsUnion -} - -// assistantMessagePartJSON contains the JSON metadata for the struct -// [AssistantMessagePart] -type assistantMessagePartJSON struct { - Type apijson.Field - ID apijson.Field - State apijson.Field - Text 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 [AssistantMessagePartsUnion] interface which you can cast to -// the specific types for more type safety. -// -// Possible runtime types of the union are [TextPart], [ToolPart], -// [AssistantMessagePartsStepStartPart]. -func (r AssistantMessagePart) AsUnion() AssistantMessagePartsUnion { - return r.union -} - -// Union satisfied by [TextPart], [ToolPart] or -// [AssistantMessagePartsStepStartPart]. -type AssistantMessagePartsUnion interface { - implementsAssistantMessagePart() -} - -func init() { - apijson.RegisterUnion( - reflect.TypeOf((*AssistantMessagePartsUnion)(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(AssistantMessagePartsStepStartPart{}), - DiscriminatorValue: "step-start", - }, - ) -} - -type AssistantMessagePartsStepStartPart struct { - Type AssistantMessagePartsStepStartPartType `json:"type,required"` - JSON assistantMessagePartsStepStartPartJSON `json:"-"` -} - -// assistantMessagePartsStepStartPartJSON contains the JSON metadata for the struct -// [AssistantMessagePartsStepStartPart] -type assistantMessagePartsStepStartPartJSON struct { - Type apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *AssistantMessagePartsStepStartPart) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r assistantMessagePartsStepStartPartJSON) RawJSON() string { - return r.raw -} - -func (r AssistantMessagePartsStepStartPart) implementsAssistantMessagePart() {} - -type AssistantMessagePartsStepStartPartType string - -const ( - AssistantMessagePartsStepStartPartTypeStepStart AssistantMessagePartsStepStartPartType = "step-start" -) - -func (r AssistantMessagePartsStepStartPartType) IsKnown() bool { - switch r { - case AssistantMessagePartsStepStartPartTypeStepStart: - return true - } - return false -} - -type AssistantMessagePartsType string - -const ( - AssistantMessagePartsTypeText AssistantMessagePartsType = "text" - AssistantMessagePartsTypeTool AssistantMessagePartsType = "tool" - AssistantMessagePartsTypeStepStart AssistantMessagePartsType = "step-start" -) - -func (r AssistantMessagePartsType) IsKnown() bool { - switch r { - case AssistantMessagePartsTypeText, AssistantMessagePartsTypeTool, AssistantMessagePartsTypeStepStart: - return true - } - return false -} - type AssistantMessagePath struct { Cwd string `json:"cwd,required"` Root string `json:"root,required"` @@ -554,6 +428,93 @@ func (r AssistantMessageErrorName) IsKnown() bool { return false } +type AssistantMessagePart struct { + Type AssistantMessagePartType `json:"type,required"` + ID string `json:"id"` + // This field can have the runtime type of [ToolPartState]. + State interface{} `json:"state"` + Text string `json:"text"` + 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 + State apijson.Field + Text 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]. +func (r AssistantMessagePart) AsUnion() AssistantMessagePartUnion { + return r.union +} + +// Union satisfied by [TextPart], [ToolPart] or [StepStartPart]. +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", + }, + ) +} + +type AssistantMessagePartType string + +const ( + AssistantMessagePartTypeText AssistantMessagePartType = "text" + AssistantMessagePartTypeTool AssistantMessagePartType = "tool" + AssistantMessagePartTypeStepStart AssistantMessagePartType = "step-start" +) + +func (r AssistantMessagePartType) IsKnown() bool { + switch r { + case AssistantMessagePartTypeText, AssistantMessagePartTypeTool, AssistantMessagePartTypeStepStart: + return true + } + return false +} + type FilePart struct { Mime string `json:"mime,required"` Type FilePartType `json:"type,required"` @@ -580,7 +541,7 @@ func (r filePartJSON) RawJSON() string { return r.raw } -func (r FilePart) implementsMessageUserMessagePart() {} +func (r FilePart) implementsUserMessagePart() {} type FilePartType string @@ -607,11 +568,11 @@ func (r FilePartParam) MarshalJSON() (data []byte, err error) { return apijson.MarshalRoot(r) } -func (r FilePartParam) implementsSessionChatParamsPartUnion() {} +func (r FilePartParam) implementsUserMessagePartUnionParam() {} type Message struct { ID string `json:"id,required"` - // This field can have the runtime type of [[]MessageUserMessagePart], + // This field can have the runtime type of [[]UserMessagePart], // [[]AssistantMessagePart]. Parts interface{} `json:"parts,required"` Role MessageRole `json:"role,required"` @@ -699,12 +660,12 @@ func init() { } type MessageUserMessage struct { - ID string `json:"id,required"` - Parts []MessageUserMessagePart `json:"parts,required"` - Role MessageUserMessageRole `json:"role,required"` - SessionID string `json:"sessionID,required"` - Time MessageUserMessageTime `json:"time,required"` - JSON messageUserMessageJSON `json:"-"` + ID string `json:"id,required"` + Parts []UserMessagePart `json:"parts,required"` + Role MessageUserMessageRole `json:"role,required"` + SessionID string `json:"sessionID,required"` + Time MessageUserMessageTime `json:"time,required"` + JSON messageUserMessageJSON `json:"-"` } // messageUserMessageJSON contains the JSON metadata for the struct @@ -729,86 +690,6 @@ func (r messageUserMessageJSON) RawJSON() string { func (r MessageUserMessage) implementsMessage() {} -type MessageUserMessagePart struct { - Type MessageUserMessagePartsType `json:"type,required"` - Filename string `json:"filename"` - Mime string `json:"mime"` - Text string `json:"text"` - URL string `json:"url"` - JSON messageUserMessagePartJSON `json:"-"` - union MessageUserMessagePartsUnion -} - -// messageUserMessagePartJSON contains the JSON metadata for the struct -// [MessageUserMessagePart] -type messageUserMessagePartJSON struct { - Type apijson.Field - Filename apijson.Field - Mime apijson.Field - Text apijson.Field - URL apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r messageUserMessagePartJSON) RawJSON() string { - return r.raw -} - -func (r *MessageUserMessagePart) UnmarshalJSON(data []byte) (err error) { - *r = MessageUserMessagePart{} - err = apijson.UnmarshalRoot(data, &r.union) - if err != nil { - return err - } - return apijson.Port(r.union, &r) -} - -// AsUnion returns a [MessageUserMessagePartsUnion] interface which you can cast to -// the specific types for more type safety. -// -// Possible runtime types of the union are [TextPart], [FilePart]. -func (r MessageUserMessagePart) AsUnion() MessageUserMessagePartsUnion { - return r.union -} - -// Union satisfied by [TextPart] or [FilePart]. -type MessageUserMessagePartsUnion interface { - implementsMessageUserMessagePart() -} - -func init() { - apijson.RegisterUnion( - reflect.TypeOf((*MessageUserMessagePartsUnion)(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", - }, - ) -} - -type MessageUserMessagePartsType string - -const ( - MessageUserMessagePartsTypeText MessageUserMessagePartsType = "text" - MessageUserMessagePartsTypeFile MessageUserMessagePartsType = "file" -) - -func (r MessageUserMessagePartsType) IsKnown() bool { - switch r { - case MessageUserMessagePartsTypeText, MessageUserMessagePartsTypeFile: - return true - } - return false -} - type MessageUserMessageRole string const ( @@ -957,6 +838,42 @@ func (r sessionShareJSON) RawJSON() string { return r.raw } +type StepStartPart struct { + Type StepStartPartType `json:"type,required"` + JSON stepStartPartJSON `json:"-"` +} + +// stepStartPartJSON contains the JSON metadata for the struct [StepStartPart] +type stepStartPartJSON struct { + Type apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *StepStartPart) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r stepStartPartJSON) RawJSON() string { + return r.raw +} + +func (r StepStartPart) implementsAssistantMessagePart() {} + +type StepStartPartType string + +const ( + StepStartPartTypeStepStart StepStartPartType = "step-start" +) + +func (r StepStartPartType) IsKnown() bool { + switch r { + case StepStartPartTypeStepStart: + return true + } + return false +} + type TextPart struct { Text string `json:"text,required"` Type TextPartType `json:"type,required"` @@ -979,11 +896,9 @@ func (r textPartJSON) RawJSON() string { return r.raw } -func (r TextPart) implementsEventListResponseEventMessagePartUpdatedPropertiesPart() {} - func (r TextPart) implementsAssistantMessagePart() {} -func (r TextPart) implementsMessageUserMessagePart() {} +func (r TextPart) implementsUserMessagePart() {} type TextPartType string @@ -1008,7 +923,7 @@ func (r TextPartParam) MarshalJSON() (data []byte, err error) { return apijson.MarshalRoot(r) } -func (r TextPartParam) implementsSessionChatParamsPartUnion() {} +func (r TextPartParam) implementsUserMessagePartUnionParam() {} type ToolPart struct { ID string `json:"id,required"` @@ -1036,19 +951,18 @@ func (r toolPartJSON) RawJSON() string { return r.raw } -func (r ToolPart) implementsEventListResponseEventMessagePartUpdatedPropertiesPart() {} - func (r ToolPart) implementsAssistantMessagePart() {} type ToolPartState struct { Status ToolPartStateStatus `json:"status,required"` + Error string `json:"error"` // This field can have the runtime type of [interface{}]. Input interface{} `json:"input"` // This field can have the runtime type of [map[string]interface{}]. Metadata interface{} `json:"metadata"` Output string `json:"output"` - // This field can have the runtime type of [ToolPartStateToolStateRunningTime], - // [ToolPartStateToolInvocationCompletedTime]. + // This field can have the runtime type of [ToolStateRunningTime], + // [ToolStateCompletedTime], [ToolStateErrorTime]. Time interface{} `json:"time"` Title string `json:"title"` JSON toolPartStateJSON `json:"-"` @@ -1058,6 +972,7 @@ type ToolPartState struct { // toolPartStateJSON contains the JSON metadata for the struct [ToolPartState] type toolPartStateJSON struct { Status apijson.Field + Error apijson.Field Input apijson.Field Metadata apijson.Field Output apijson.Field @@ -1083,14 +998,14 @@ func (r *ToolPartState) UnmarshalJSON(data []byte) (err error) { // AsUnion returns a [ToolPartStateUnion] interface which you can cast to the // specific types for more type safety. // -// Possible runtime types of the union are [ToolPartStateToolStatePending], -// [ToolPartStateToolStateRunning], [ToolPartStateToolInvocationCompleted]. +// Possible runtime types of the union are [ToolStatePending], [ToolStateRunning], +// [ToolStateCompleted], [ToolStateError]. func (r ToolPartState) AsUnion() ToolPartStateUnion { return r.union } -// Union satisfied by [ToolPartStateToolStatePending], -// [ToolPartStateToolStateRunning] or [ToolPartStateToolInvocationCompleted]. +// Union satisfied by [ToolStatePending], [ToolStateRunning], [ToolStateCompleted] +// or [ToolStateError]. type ToolPartStateUnion interface { implementsToolPartState() } @@ -1101,202 +1016,39 @@ func init() { "status", apijson.UnionVariant{ TypeFilter: gjson.JSON, - Type: reflect.TypeOf(ToolPartStateToolStatePending{}), + Type: reflect.TypeOf(ToolStatePending{}), DiscriminatorValue: "pending", }, apijson.UnionVariant{ TypeFilter: gjson.JSON, - Type: reflect.TypeOf(ToolPartStateToolStateRunning{}), + Type: reflect.TypeOf(ToolStateRunning{}), DiscriminatorValue: "running", }, apijson.UnionVariant{ TypeFilter: gjson.JSON, - Type: reflect.TypeOf(ToolPartStateToolInvocationCompleted{}), + Type: reflect.TypeOf(ToolStateCompleted{}), DiscriminatorValue: "completed", }, + apijson.UnionVariant{ + TypeFilter: gjson.JSON, + Type: reflect.TypeOf(ToolStateError{}), + DiscriminatorValue: "error", + }, ) } -type ToolPartStateToolStatePending struct { - Status ToolPartStateToolStatePendingStatus `json:"status,required"` - JSON toolPartStateToolStatePendingJSON `json:"-"` -} - -// toolPartStateToolStatePendingJSON contains the JSON metadata for the struct -// [ToolPartStateToolStatePending] -type toolPartStateToolStatePendingJSON struct { - Status apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *ToolPartStateToolStatePending) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r toolPartStateToolStatePendingJSON) RawJSON() string { - return r.raw -} - -func (r ToolPartStateToolStatePending) implementsToolPartState() {} - -type ToolPartStateToolStatePendingStatus string - -const ( - ToolPartStateToolStatePendingStatusPending ToolPartStateToolStatePendingStatus = "pending" -) - -func (r ToolPartStateToolStatePendingStatus) IsKnown() bool { - switch r { - case ToolPartStateToolStatePendingStatusPending: - return true - } - return false -} - -type ToolPartStateToolStateRunning struct { - Status ToolPartStateToolStateRunningStatus `json:"status,required"` - Time ToolPartStateToolStateRunningTime `json:"time,required"` - Input interface{} `json:"input"` - JSON toolPartStateToolStateRunningJSON `json:"-"` -} - -// toolPartStateToolStateRunningJSON contains the JSON metadata for the struct -// [ToolPartStateToolStateRunning] -type toolPartStateToolStateRunningJSON struct { - Status apijson.Field - Time apijson.Field - Input apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *ToolPartStateToolStateRunning) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r toolPartStateToolStateRunningJSON) RawJSON() string { - return r.raw -} - -func (r ToolPartStateToolStateRunning) implementsToolPartState() {} - -type ToolPartStateToolStateRunningStatus string - -const ( - ToolPartStateToolStateRunningStatusRunning ToolPartStateToolStateRunningStatus = "running" -) - -func (r ToolPartStateToolStateRunningStatus) IsKnown() bool { - switch r { - case ToolPartStateToolStateRunningStatusRunning: - return true - } - return false -} - -type ToolPartStateToolStateRunningTime struct { - Start float64 `json:"start,required"` - JSON toolPartStateToolStateRunningTimeJSON `json:"-"` -} - -// toolPartStateToolStateRunningTimeJSON contains the JSON metadata for the struct -// [ToolPartStateToolStateRunningTime] -type toolPartStateToolStateRunningTimeJSON struct { - Start apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *ToolPartStateToolStateRunningTime) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r toolPartStateToolStateRunningTimeJSON) RawJSON() string { - return r.raw -} - -type ToolPartStateToolInvocationCompleted struct { - Metadata map[string]interface{} `json:"metadata,required"` - Output string `json:"output,required"` - Status ToolPartStateToolInvocationCompletedStatus `json:"status,required"` - Time ToolPartStateToolInvocationCompletedTime `json:"time,required"` - Title string `json:"title,required"` - Input interface{} `json:"input"` - JSON toolPartStateToolInvocationCompletedJSON `json:"-"` -} - -// toolPartStateToolInvocationCompletedJSON contains the JSON metadata for the -// struct [ToolPartStateToolInvocationCompleted] -type toolPartStateToolInvocationCompletedJSON struct { - Metadata apijson.Field - Output apijson.Field - Status apijson.Field - Time apijson.Field - Title apijson.Field - Input apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *ToolPartStateToolInvocationCompleted) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r toolPartStateToolInvocationCompletedJSON) RawJSON() string { - return r.raw -} - -func (r ToolPartStateToolInvocationCompleted) implementsToolPartState() {} - -type ToolPartStateToolInvocationCompletedStatus string - -const ( - ToolPartStateToolInvocationCompletedStatusCompleted ToolPartStateToolInvocationCompletedStatus = "completed" -) - -func (r ToolPartStateToolInvocationCompletedStatus) IsKnown() bool { - switch r { - case ToolPartStateToolInvocationCompletedStatusCompleted: - return true - } - return false -} - -type ToolPartStateToolInvocationCompletedTime struct { - End float64 `json:"end,required"` - Start float64 `json:"start,required"` - JSON toolPartStateToolInvocationCompletedTimeJSON `json:"-"` -} - -// toolPartStateToolInvocationCompletedTimeJSON contains the JSON metadata for the -// struct [ToolPartStateToolInvocationCompletedTime] -type toolPartStateToolInvocationCompletedTimeJSON struct { - End apijson.Field - Start apijson.Field - raw string - ExtraFields map[string]apijson.Field -} - -func (r *ToolPartStateToolInvocationCompletedTime) UnmarshalJSON(data []byte) (err error) { - return apijson.UnmarshalRoot(data, r) -} - -func (r toolPartStateToolInvocationCompletedTimeJSON) RawJSON() string { - return r.raw -} - type ToolPartStateStatus string const ( ToolPartStateStatusPending ToolPartStateStatus = "pending" ToolPartStateStatusRunning ToolPartStateStatus = "running" ToolPartStateStatusCompleted ToolPartStateStatus = "completed" + ToolPartStateStatusError ToolPartStateStatus = "error" ) func (r ToolPartStateStatus) IsKnown() bool { switch r { - case ToolPartStateStatusPending, ToolPartStateStatusRunning, ToolPartStateStatusCompleted: + case ToolPartStateStatusPending, ToolPartStateStatusRunning, ToolPartStateStatusCompleted, ToolPartStateStatusError: return true } return false @@ -1316,50 +1068,352 @@ func (r ToolPartType) IsKnown() bool { return false } +type ToolStateCompleted struct { + Metadata map[string]interface{} `json:"metadata,required"` + Output string `json:"output,required"` + Status ToolStateCompletedStatus `json:"status,required"` + Time ToolStateCompletedTime `json:"time,required"` + Title string `json:"title,required"` + Input interface{} `json:"input"` + JSON toolStateCompletedJSON `json:"-"` +} + +// toolStateCompletedJSON contains the JSON metadata for the struct +// [ToolStateCompleted] +type toolStateCompletedJSON struct { + Metadata apijson.Field + Output apijson.Field + Status apijson.Field + Time apijson.Field + Title apijson.Field + Input apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ToolStateCompleted) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r toolStateCompletedJSON) RawJSON() string { + return r.raw +} + +func (r ToolStateCompleted) implementsToolPartState() {} + +type ToolStateCompletedStatus string + +const ( + ToolStateCompletedStatusCompleted ToolStateCompletedStatus = "completed" +) + +func (r ToolStateCompletedStatus) IsKnown() bool { + switch r { + case ToolStateCompletedStatusCompleted: + return true + } + return false +} + +type ToolStateCompletedTime struct { + End float64 `json:"end,required"` + Start float64 `json:"start,required"` + JSON toolStateCompletedTimeJSON `json:"-"` +} + +// toolStateCompletedTimeJSON contains the JSON metadata for the struct +// [ToolStateCompletedTime] +type toolStateCompletedTimeJSON struct { + End apijson.Field + Start apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ToolStateCompletedTime) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r toolStateCompletedTimeJSON) RawJSON() string { + return r.raw +} + +type ToolStateError struct { + Error string `json:"error,required"` + Status ToolStateErrorStatus `json:"status,required"` + Time ToolStateErrorTime `json:"time,required"` + Input interface{} `json:"input"` + JSON toolStateErrorJSON `json:"-"` +} + +// toolStateErrorJSON contains the JSON metadata for the struct [ToolStateError] +type toolStateErrorJSON struct { + Error apijson.Field + Status apijson.Field + Time apijson.Field + Input apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ToolStateError) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r toolStateErrorJSON) RawJSON() string { + return r.raw +} + +func (r ToolStateError) implementsToolPartState() {} + +type ToolStateErrorStatus string + +const ( + ToolStateErrorStatusError ToolStateErrorStatus = "error" +) + +func (r ToolStateErrorStatus) IsKnown() bool { + switch r { + case ToolStateErrorStatusError: + return true + } + return false +} + +type ToolStateErrorTime struct { + End float64 `json:"end,required"` + Start float64 `json:"start,required"` + JSON toolStateErrorTimeJSON `json:"-"` +} + +// toolStateErrorTimeJSON contains the JSON metadata for the struct +// [ToolStateErrorTime] +type toolStateErrorTimeJSON struct { + End apijson.Field + Start apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ToolStateErrorTime) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r toolStateErrorTimeJSON) RawJSON() string { + return r.raw +} + +type ToolStatePending struct { + Status ToolStatePendingStatus `json:"status,required"` + JSON toolStatePendingJSON `json:"-"` +} + +// toolStatePendingJSON contains the JSON metadata for the struct +// [ToolStatePending] +type toolStatePendingJSON struct { + Status apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ToolStatePending) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r toolStatePendingJSON) RawJSON() string { + return r.raw +} + +func (r ToolStatePending) implementsToolPartState() {} + +type ToolStatePendingStatus string + +const ( + ToolStatePendingStatusPending ToolStatePendingStatus = "pending" +) + +func (r ToolStatePendingStatus) IsKnown() bool { + switch r { + case ToolStatePendingStatusPending: + return true + } + return false +} + +type ToolStateRunning struct { + Status ToolStateRunningStatus `json:"status,required"` + Time ToolStateRunningTime `json:"time,required"` + Input interface{} `json:"input"` + Metadata map[string]interface{} `json:"metadata"` + Title string `json:"title"` + JSON toolStateRunningJSON `json:"-"` +} + +// toolStateRunningJSON contains the JSON metadata for the struct +// [ToolStateRunning] +type toolStateRunningJSON struct { + Status apijson.Field + Time apijson.Field + Input apijson.Field + Metadata apijson.Field + Title apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ToolStateRunning) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r toolStateRunningJSON) RawJSON() string { + return r.raw +} + +func (r ToolStateRunning) implementsToolPartState() {} + +type ToolStateRunningStatus string + +const ( + ToolStateRunningStatusRunning ToolStateRunningStatus = "running" +) + +func (r ToolStateRunningStatus) IsKnown() bool { + switch r { + case ToolStateRunningStatusRunning: + return true + } + return false +} + +type ToolStateRunningTime struct { + Start float64 `json:"start,required"` + JSON toolStateRunningTimeJSON `json:"-"` +} + +// toolStateRunningTimeJSON contains the JSON metadata for the struct +// [ToolStateRunningTime] +type toolStateRunningTimeJSON struct { + Start apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r *ToolStateRunningTime) UnmarshalJSON(data []byte) (err error) { + return apijson.UnmarshalRoot(data, r) +} + +func (r toolStateRunningTimeJSON) RawJSON() string { + return r.raw +} + +type UserMessagePart struct { + Type UserMessagePartType `json:"type,required"` + Filename string `json:"filename"` + Mime string `json:"mime"` + Text string `json:"text"` + URL string `json:"url"` + JSON userMessagePartJSON `json:"-"` + union UserMessagePartUnion +} + +// userMessagePartJSON contains the JSON metadata for the struct [UserMessagePart] +type userMessagePartJSON struct { + Type apijson.Field + Filename apijson.Field + Mime apijson.Field + Text apijson.Field + URL apijson.Field + raw string + ExtraFields map[string]apijson.Field +} + +func (r userMessagePartJSON) 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) +} + +// 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 +} + +// Union satisfied by [TextPart] or [FilePart]. +type UserMessagePartUnion interface { + implementsUserMessagePart() +} + +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", + }, + ) +} + +type UserMessagePartType string + +const ( + UserMessagePartTypeText UserMessagePartType = "text" + UserMessagePartTypeFile UserMessagePartType = "file" +) + +func (r UserMessagePartType) IsKnown() bool { + switch r { + case UserMessagePartTypeText, UserMessagePartTypeFile: + 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"` + 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 { - ModelID param.Field[string] `json:"modelID,required"` - Parts param.Field[[]SessionChatParamsPartUnion] `json:"parts,required"` - ProviderID param.Field[string] `json:"providerID,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 SessionChatParamsPart struct { - Type param.Field[SessionChatParamsPartsType] `json:"type,required"` - Filename param.Field[string] `json:"filename"` - Mime param.Field[string] `json:"mime"` - Text param.Field[string] `json:"text"` - URL param.Field[string] `json:"url"` -} - -func (r SessionChatParamsPart) MarshalJSON() (data []byte, err error) { - return apijson.MarshalRoot(r) -} - -func (r SessionChatParamsPart) implementsSessionChatParamsPartUnion() {} - -// Satisfied by [TextPartParam], [FilePartParam], [SessionChatParamsPart]. -type SessionChatParamsPartUnion interface { - implementsSessionChatParamsPartUnion() -} - -type SessionChatParamsPartsType string - -const ( - SessionChatParamsPartsTypeText SessionChatParamsPartsType = "text" - SessionChatParamsPartsTypeFile SessionChatParamsPartsType = "file" -) - -func (r SessionChatParamsPartsType) IsKnown() bool { - switch r { - case SessionChatParamsPartsTypeText, SessionChatParamsPartsTypeFile: - return true - } - return false -} - type SessionInitParams struct { 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 320f27b9..15137e62 100644 --- a/packages/tui/sdk/session_test.go +++ b/packages/tui/sdk/session_test.go @@ -118,7 +118,7 @@ func TestSessionChat(t *testing.T) { "id", opencode.SessionChatParams{ ModelID: opencode.F("modelID"), - Parts: opencode.F([]opencode.SessionChatParamsPartUnion{opencode.TextPartParam{ + Parts: opencode.F([]opencode.UserMessagePartUnionParam{opencode.TextPartParam{ Text: opencode.F("text"), Type: opencode.F(opencode.TextPartTypeText), }}), diff --git a/stainless.yml b/stainless.yml index bd705571..44479bfa 100644 --- a/stainless.yml +++ b/stainless.yml @@ -81,7 +81,15 @@ resources: textPart: TextPart filePart: FilePart toolPart: ToolPart + stepStartPart: StepStartPart assistantMessage: AssistantMessage + userMessagePart: UserMessagePart + assistantMessagePart: AssistantMessagePart + toolStatePending: ToolStatePending + toolStateRunning: ToolStateRunning + toolStateCompleted: ToolStateCompleted + toolStateError: ToolStateError + methods: list: get /session create: post /session