Просмотр исходного кода

wip: file part source in server/api (optional)

adamdotdevin 7 месяцев назад
Родитель
Сommit
2bf9d5d4ec

+ 8 - 1
packages/opencode/src/session/index.ts

@@ -490,6 +490,12 @@ export namespace Session {
                     synthetic: true,
                     text: result.output,
                   },
+                  {
+                    ...part,
+                    id: part.id ?? Identifier.ascending("part"),
+                    messageID: userMsg.id,
+                    sessionID: input.sessionID,
+                  },
                 ]
               }
 
@@ -505,13 +511,14 @@ export namespace Session {
                   synthetic: true,
                 },
                 {
-                  id: Identifier.ascending("part"),
+                  id: part.id ?? Identifier.ascending("part"),
                   messageID: userMsg.id,
                   sessionID: input.sessionID,
                   type: "file",
                   url: `data:${part.mime};base64,` + Buffer.from(await file.bytes()).toString("base64"),
                   mime: part.mime,
                   filename: part.filename!,
+                  source: part.source,
                 },
               ]
           }

+ 37 - 1
packages/opencode/src/session/message-v2.ts

@@ -4,6 +4,7 @@ import { NamedError } from "../util/error"
 import { Message } from "./message"
 import { convertToModelMessages, type ModelMessage, type UIMessage } from "ai"
 import { Identifier } from "../id/id"
+import { LSP } from "../lsp"
 
 export namespace MessageV2 {
   export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
@@ -118,11 +119,45 @@ export namespace MessageV2 {
   })
   export type ToolPart = z.infer<typeof ToolPart>
 
+  const FilePartSourceBase = z.object({
+    text: z
+      .object({
+        value: z.string(),
+        start: z.number().int(),
+        end: z.number().int(),
+      })
+      .openapi({
+        ref: "FilePartSourceText",
+      }),
+  })
+
+  export const FileSource = FilePartSourceBase.extend({
+    type: z.literal("file"),
+    path: z.string(),
+  }).openapi({
+    ref: "FileSource",
+  })
+
+  export const SymbolSource = FilePartSourceBase.extend({
+    type: z.literal("symbol"),
+    path: z.string(),
+    range: LSP.Range,
+    name: z.string(),
+    kind: z.number().int(),
+  }).openapi({
+    ref: "SymbolSource",
+  })
+
+  export const FilePartSource = z.discriminatedUnion("type", [FileSource, SymbolSource]).openapi({
+    ref: "FilePartSource",
+  })
+
   export const FilePart = PartBase.extend({
     type: z.literal("file"),
     mime: z.string(),
     filename: z.string().optional(),
     url: z.string(),
+    source: FilePartSource.optional(),
   }).openapi({
     ref: "FilePart",
   })
@@ -394,7 +429,8 @@ export namespace MessageV2 {
                   text: part.text,
                 },
               ]
-            if (part.type === "file")
+            // text/plain files are converted into text parts, ignore them
+            if (part.type === "file" && part.mime !== "text/plain")
               return [
                 {
                   type: "file",

+ 3 - 3
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-a1da357fcefd3105736841fbf44018022fade78e67ffc81e178cf9196da723ee.yml
-openapi_spec_hash: 9bd27afcc5b8f43d8e4223f7c984035f
-config_hash: 62b73a3397120578a992bffd1e69386a
+openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/opencode%2Fopencode-e7f4ac9b5afd5c6db4741a27b5445167808b0a3b7c36dfd525bfb3446a11a253.yml
+openapi_spec_hash: 3e7b367a173d6de7924f35a41ac6b5a5
+config_hash: 6d56a7ca0d6ed899ecdb5c053a8278ae

+ 8 - 0
packages/tui/sdk/api.md

@@ -77,18 +77,26 @@ Methods:
 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#FilePartInputParam">FilePartInputParam</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#FilePartSourceUnionParam">FilePartSourceUnionParam</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#FilePartSourceTextParam">FilePartSourceTextParam</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#FileSourceParam">FileSourceParam</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#SymbolSourceParam">SymbolSourceParam</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#TextPartInputParam">TextPartInputParam</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#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#FilePartSource">FilePartSource</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#FilePartSourceText">FilePartSourceText</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#FileSource">FileSource</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#SnapshotPart">SnapshotPart</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#SymbolSource">SymbolSource</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>
 - <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#ToolStateCompleted">ToolStateCompleted</a>

+ 4 - 0
packages/tui/sdk/config.go

@@ -70,6 +70,9 @@ type Config struct {
 	// Control sharing behavior:'manual' allows manual sharing via commands, 'auto'
 	// enables automatic sharing, 'disabled' disables all sharing
 	Share ConfigShare `json:"share"`
+	// Small model to use for tasks like summarization and title generation in the
+	// format of provider/model
+	SmallModel string `json:"small_model"`
 	// Theme name to use for the interface
 	Theme string `json:"theme"`
 	// Custom username to display in conversations instead of system username
@@ -93,6 +96,7 @@ type configJSON struct {
 	Model             apijson.Field
 	Provider          apijson.Field
 	Share             apijson.Field
+	SmallModel        apijson.Field
 	Theme             apijson.Field
 	Username          apijson.Field
 	raw               string

+ 374 - 22
packages/tui/sdk/session.go

@@ -434,14 +434,15 @@ func (r AssistantMessageErrorName) IsKnown() bool {
 }
 
 type FilePart struct {
-	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:"-"`
+	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"`
+	Source    FilePartSource `json:"source"`
+	JSON      filePartJSON   `json:"-"`
 }
 
 // filePartJSON contains the JSON metadata for the struct [FilePart]
@@ -453,6 +454,7 @@ type filePartJSON struct {
 	Type        apijson.Field
 	URL         apijson.Field
 	Filename    apijson.Field
+	Source      apijson.Field
 	raw         string
 	ExtraFields map[string]apijson.Field
 }
@@ -482,11 +484,12 @@ func (r FilePartType) IsKnown() bool {
 }
 
 type FilePartInputParam struct {
-	Mime     param.Field[string]            `json:"mime,required"`
-	Type     param.Field[FilePartInputType] `json:"type,required"`
-	URL      param.Field[string]            `json:"url,required"`
-	ID       param.Field[string]            `json:"id"`
-	Filename param.Field[string]            `json:"filename"`
+	Mime     param.Field[string]                   `json:"mime,required"`
+	Type     param.Field[FilePartInputType]        `json:"type,required"`
+	URL      param.Field[string]                   `json:"url,required"`
+	ID       param.Field[string]                   `json:"id"`
+	Filename param.Field[string]                   `json:"filename"`
+	Source   param.Field[FilePartSourceUnionParam] `json:"source"`
 }
 
 func (r FilePartInputParam) MarshalJSON() (data []byte, err error) {
@@ -509,6 +512,195 @@ func (r FilePartInputType) IsKnown() bool {
 	return false
 }
 
+type FilePartSource struct {
+	Path string             `json:"path,required"`
+	Text FilePartSourceText `json:"text,required"`
+	Type FilePartSourceType `json:"type,required"`
+	Kind int64              `json:"kind"`
+	Name string             `json:"name"`
+	// This field can have the runtime type of [SymbolSourceRange].
+	Range interface{}        `json:"range"`
+	JSON  filePartSourceJSON `json:"-"`
+	union FilePartSourceUnion
+}
+
+// filePartSourceJSON contains the JSON metadata for the struct [FilePartSource]
+type filePartSourceJSON struct {
+	Path        apijson.Field
+	Text        apijson.Field
+	Type        apijson.Field
+	Kind        apijson.Field
+	Name        apijson.Field
+	Range       apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r filePartSourceJSON) RawJSON() string {
+	return r.raw
+}
+
+func (r *FilePartSource) UnmarshalJSON(data []byte) (err error) {
+	*r = FilePartSource{}
+	err = apijson.UnmarshalRoot(data, &r.union)
+	if err != nil {
+		return err
+	}
+	return apijson.Port(r.union, &r)
+}
+
+// AsUnion returns a [FilePartSourceUnion] interface which you can cast to the
+// specific types for more type safety.
+//
+// Possible runtime types of the union are [FileSource], [SymbolSource].
+func (r FilePartSource) AsUnion() FilePartSourceUnion {
+	return r.union
+}
+
+// Union satisfied by [FileSource] or [SymbolSource].
+type FilePartSourceUnion interface {
+	implementsFilePartSource()
+}
+
+func init() {
+	apijson.RegisterUnion(
+		reflect.TypeOf((*FilePartSourceUnion)(nil)).Elem(),
+		"type",
+		apijson.UnionVariant{
+			TypeFilter:         gjson.JSON,
+			Type:               reflect.TypeOf(FileSource{}),
+			DiscriminatorValue: "file",
+		},
+		apijson.UnionVariant{
+			TypeFilter:         gjson.JSON,
+			Type:               reflect.TypeOf(SymbolSource{}),
+			DiscriminatorValue: "symbol",
+		},
+	)
+}
+
+type FilePartSourceType string
+
+const (
+	FilePartSourceTypeFile   FilePartSourceType = "file"
+	FilePartSourceTypeSymbol FilePartSourceType = "symbol"
+)
+
+func (r FilePartSourceType) IsKnown() bool {
+	switch r {
+	case FilePartSourceTypeFile, FilePartSourceTypeSymbol:
+		return true
+	}
+	return false
+}
+
+type FilePartSourceParam struct {
+	Path  param.Field[string]                  `json:"path,required"`
+	Text  param.Field[FilePartSourceTextParam] `json:"text,required"`
+	Type  param.Field[FilePartSourceType]      `json:"type,required"`
+	Kind  param.Field[int64]                   `json:"kind"`
+	Name  param.Field[string]                  `json:"name"`
+	Range param.Field[interface{}]             `json:"range"`
+}
+
+func (r FilePartSourceParam) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
+func (r FilePartSourceParam) implementsFilePartSourceUnionParam() {}
+
+// Satisfied by [FileSourceParam], [SymbolSourceParam], [FilePartSourceParam].
+type FilePartSourceUnionParam interface {
+	implementsFilePartSourceUnionParam()
+}
+
+type FilePartSourceText struct {
+	End   int64                  `json:"end,required"`
+	Start int64                  `json:"start,required"`
+	Value string                 `json:"value,required"`
+	JSON  filePartSourceTextJSON `json:"-"`
+}
+
+// filePartSourceTextJSON contains the JSON metadata for the struct
+// [FilePartSourceText]
+type filePartSourceTextJSON struct {
+	End         apijson.Field
+	Start       apijson.Field
+	Value       apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *FilePartSourceText) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r filePartSourceTextJSON) RawJSON() string {
+	return r.raw
+}
+
+type FilePartSourceTextParam struct {
+	End   param.Field[int64]  `json:"end,required"`
+	Start param.Field[int64]  `json:"start,required"`
+	Value param.Field[string] `json:"value,required"`
+}
+
+func (r FilePartSourceTextParam) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
+type FileSource struct {
+	Path string             `json:"path,required"`
+	Text FilePartSourceText `json:"text,required"`
+	Type FileSourceType     `json:"type,required"`
+	JSON fileSourceJSON     `json:"-"`
+}
+
+// fileSourceJSON contains the JSON metadata for the struct [FileSource]
+type fileSourceJSON struct {
+	Path        apijson.Field
+	Text        apijson.Field
+	Type        apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *FileSource) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r fileSourceJSON) RawJSON() string {
+	return r.raw
+}
+
+func (r FileSource) implementsFilePartSource() {}
+
+type FileSourceType string
+
+const (
+	FileSourceTypeFile FileSourceType = "file"
+)
+
+func (r FileSourceType) IsKnown() bool {
+	switch r {
+	case FileSourceTypeFile:
+		return true
+	}
+	return false
+}
+
+type FileSourceParam struct {
+	Path param.Field[string]                  `json:"path,required"`
+	Text param.Field[FilePartSourceTextParam] `json:"text,required"`
+	Type param.Field[FileSourceType]          `json:"type,required"`
+}
+
+func (r FileSourceParam) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
+func (r FileSourceParam) implementsFilePartSourceUnionParam() {}
+
 type Message struct {
 	ID        string      `json:"id,required"`
 	Role      MessageRole `json:"role,required"`
@@ -609,15 +801,16 @@ func (r MessageRole) IsKnown() bool {
 }
 
 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"`
-	Snapshot  string   `json:"snapshot"`
+	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"`
+	Snapshot  string         `json:"snapshot"`
+	Source    FilePartSource `json:"source"`
 	// This field can have the runtime type of [ToolPartState].
 	State     interface{} `json:"state"`
 	Synthetic bool        `json:"synthetic"`
@@ -643,6 +836,7 @@ type partJSON struct {
 	Filename    apijson.Field
 	Mime        apijson.Field
 	Snapshot    apijson.Field
+	Source      apijson.Field
 	State       apijson.Field
 	Synthetic   apijson.Field
 	Text        apijson.Field
@@ -1018,6 +1212,163 @@ func (r StepStartPartType) IsKnown() bool {
 	return false
 }
 
+type SymbolSource struct {
+	Kind  int64              `json:"kind,required"`
+	Name  string             `json:"name,required"`
+	Path  string             `json:"path,required"`
+	Range SymbolSourceRange  `json:"range,required"`
+	Text  FilePartSourceText `json:"text,required"`
+	Type  SymbolSourceType   `json:"type,required"`
+	JSON  symbolSourceJSON   `json:"-"`
+}
+
+// symbolSourceJSON contains the JSON metadata for the struct [SymbolSource]
+type symbolSourceJSON struct {
+	Kind        apijson.Field
+	Name        apijson.Field
+	Path        apijson.Field
+	Range       apijson.Field
+	Text        apijson.Field
+	Type        apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *SymbolSource) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r symbolSourceJSON) RawJSON() string {
+	return r.raw
+}
+
+func (r SymbolSource) implementsFilePartSource() {}
+
+type SymbolSourceRange struct {
+	End   SymbolSourceRangeEnd   `json:"end,required"`
+	Start SymbolSourceRangeStart `json:"start,required"`
+	JSON  symbolSourceRangeJSON  `json:"-"`
+}
+
+// symbolSourceRangeJSON contains the JSON metadata for the struct
+// [SymbolSourceRange]
+type symbolSourceRangeJSON struct {
+	End         apijson.Field
+	Start       apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *SymbolSourceRange) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r symbolSourceRangeJSON) RawJSON() string {
+	return r.raw
+}
+
+type SymbolSourceRangeEnd struct {
+	Character float64                  `json:"character,required"`
+	Line      float64                  `json:"line,required"`
+	JSON      symbolSourceRangeEndJSON `json:"-"`
+}
+
+// symbolSourceRangeEndJSON contains the JSON metadata for the struct
+// [SymbolSourceRangeEnd]
+type symbolSourceRangeEndJSON struct {
+	Character   apijson.Field
+	Line        apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *SymbolSourceRangeEnd) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r symbolSourceRangeEndJSON) RawJSON() string {
+	return r.raw
+}
+
+type SymbolSourceRangeStart struct {
+	Character float64                    `json:"character,required"`
+	Line      float64                    `json:"line,required"`
+	JSON      symbolSourceRangeStartJSON `json:"-"`
+}
+
+// symbolSourceRangeStartJSON contains the JSON metadata for the struct
+// [SymbolSourceRangeStart]
+type symbolSourceRangeStartJSON struct {
+	Character   apijson.Field
+	Line        apijson.Field
+	raw         string
+	ExtraFields map[string]apijson.Field
+}
+
+func (r *SymbolSourceRangeStart) UnmarshalJSON(data []byte) (err error) {
+	return apijson.UnmarshalRoot(data, r)
+}
+
+func (r symbolSourceRangeStartJSON) RawJSON() string {
+	return r.raw
+}
+
+type SymbolSourceType string
+
+const (
+	SymbolSourceTypeSymbol SymbolSourceType = "symbol"
+)
+
+func (r SymbolSourceType) IsKnown() bool {
+	switch r {
+	case SymbolSourceTypeSymbol:
+		return true
+	}
+	return false
+}
+
+type SymbolSourceParam struct {
+	Kind  param.Field[int64]                   `json:"kind,required"`
+	Name  param.Field[string]                  `json:"name,required"`
+	Path  param.Field[string]                  `json:"path,required"`
+	Range param.Field[SymbolSourceRangeParam]  `json:"range,required"`
+	Text  param.Field[FilePartSourceTextParam] `json:"text,required"`
+	Type  param.Field[SymbolSourceType]        `json:"type,required"`
+}
+
+func (r SymbolSourceParam) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
+func (r SymbolSourceParam) implementsFilePartSourceUnionParam() {}
+
+type SymbolSourceRangeParam struct {
+	End   param.Field[SymbolSourceRangeEndParam]   `json:"end,required"`
+	Start param.Field[SymbolSourceRangeStartParam] `json:"start,required"`
+}
+
+func (r SymbolSourceRangeParam) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
+type SymbolSourceRangeEndParam struct {
+	Character param.Field[float64] `json:"character,required"`
+	Line      param.Field[float64] `json:"line,required"`
+}
+
+func (r SymbolSourceRangeEndParam) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
+type SymbolSourceRangeStartParam struct {
+	Character param.Field[float64] `json:"character,required"`
+	Line      param.Field[float64] `json:"line,required"`
+}
+
+func (r SymbolSourceRangeStartParam) MarshalJSON() (data []byte, err error) {
+	return apijson.MarshalRoot(r)
+}
+
 type TextPart struct {
 	ID        string       `json:"id,required"`
 	MessageID string       `json:"messageID,required"`
@@ -1614,6 +1965,7 @@ type SessionChatParamsPart struct {
 	ID        param.Field[string]                     `json:"id"`
 	Filename  param.Field[string]                     `json:"filename"`
 	Mime      param.Field[string]                     `json:"mime"`
+	Source    param.Field[FilePartSourceUnionParam]   `json:"source"`
 	Synthetic param.Field[bool]                       `json:"synthetic"`
 	Text      param.Field[string]                     `json:"text"`
 	Time      param.Field[interface{}]                `json:"time"`

+ 4 - 0
stainless.yml

@@ -94,6 +94,10 @@ resources:
       textPartInput: TextPartInput
       filePart: FilePart
       filePartInput: FilePartInput
+      filePartSourceText: FilePartSourceText
+      filePartSource: FilePartSource
+      fileSource: FileSource
+      symbolSource: SymbolSource
       toolPart: ToolPart
       stepStartPart: StepStartPart
       stepFinishPart: StepFinishPart