adamdottv 8 месяцев назад
Родитель
Сommit
97837d2d23

+ 32 - 23
packages/opencode/src/provider/models.ts

@@ -7,31 +7,40 @@ export namespace ModelsDev {
   const log = Log.create({ service: "models.dev" })
   const log = Log.create({ service: "models.dev" })
   const filepath = path.join(Global.Path.cache, "models.json")
   const filepath = path.join(Global.Path.cache, "models.json")
 
 
-  export const Model = z.object({
-    name: z.string(),
-    attachment: z.boolean(),
-    reasoning: z.boolean(),
-    temperature: z.boolean(),
-    cost: z.object({
-      input: z.number(),
-      output: z.number(),
-      inputCached: z.number(),
-      outputCached: z.number(),
-    }),
-    limit: z.object({
-      context: z.number(),
-      output: z.number(),
-    }),
-    id: z.string(),
-  })
+  export const Model = z
+    .object({
+      name: z.string(),
+      attachment: z.boolean(),
+      reasoning: z.boolean(),
+      temperature: z.boolean(),
+      cost: z.object({
+        input: z.number(),
+        output: z.number(),
+        inputCached: z.number(),
+        outputCached: z.number(),
+      }),
+      limit: z.object({
+        context: z.number(),
+        output: z.number(),
+      }),
+      id: z.string(),
+    })
+    .openapi({
+      ref: "Model.Info",
+    })
   export type Model = z.infer<typeof Model>
   export type Model = z.infer<typeof Model>
 
 
-  export const Provider = z.object({
-    name: z.string(),
-    env: z.array(z.string()),
-    id: z.string(),
-    models: z.record(Model),
-  })
+  export const Provider = z
+    .object({
+      name: z.string(),
+      env: z.array(z.string()),
+      id: z.string(),
+      models: z.record(Model),
+    })
+    .openapi({
+      ref: "Provider.Info",
+    })
+
   export type Provider = z.infer<typeof Provider>
   export type Provider = z.infer<typeof Provider>
 
 
   export async function get() {
   export async function get() {

+ 33 - 16
packages/tui/internal/app/app.go

@@ -23,7 +23,7 @@ type App struct {
 	Config     *config.Config
 	Config     *config.Config
 	Client     *client.ClientWithResponses
 	Client     *client.ClientWithResponses
 	Provider   *client.ProviderInfo
 	Provider   *client.ProviderInfo
-	Model      *client.ProviderModel
+	Model      *client.ModelInfo
 	Session    *client.SessionInfo
 	Session    *client.SessionInfo
 	Messages   []client.MessageInfo
 	Messages   []client.MessageInfo
 	Status     status.Service
 	Status     status.Service
@@ -61,20 +61,25 @@ func New(ctx context.Context, version string, httpClient *client.ClientWithRespo
 	}
 	}
 	providers := []client.ProviderInfo{}
 	providers := []client.ProviderInfo{}
 	var defaultProvider *client.ProviderInfo
 	var defaultProvider *client.ProviderInfo
-	var defaultModel *client.ProviderModel
-
-	for i, provider := range providersResponse.JSON200.Providers {
-		if i == 0 || provider.Id == "anthropic" {
-			defaultProvider = &providersResponse.JSON200.Providers[i]
-			if match, ok := providersResponse.JSON200.Default[provider.Id]; ok {
-				model := defaultProvider.Models[match]
-				defaultModel = &model
-			} else {
-				for _, model := range provider.Models {
-					defaultModel = &model
-					break
-				}
-			}
+	var defaultModel *client.ModelInfo
+
+	var anthropic *client.ProviderInfo
+	for _, provider := range providersResponse.JSON200.Providers {
+		if provider.Id == "anthropic" {
+			anthropic = &provider
+		}
+	}
+
+	// default to anthropic if available
+	if anthropic != nil {
+		defaultProvider = anthropic
+		defaultModel = getDefaultModel(providersResponse, *anthropic)
+	}
+
+	for _, provider := range providersResponse.JSON200.Providers {
+		if defaultProvider == nil || defaultModel == nil {
+			defaultProvider = &provider
+			defaultModel = getDefaultModel(providersResponse, provider)
 		}
 		}
 		providers = append(providers, provider)
 		providers = append(providers, provider)
 	}
 	}
@@ -91,7 +96,7 @@ func New(ctx context.Context, version string, httpClient *client.ClientWithRespo
 	}
 	}
 
 
 	var currentProvider *client.ProviderInfo
 	var currentProvider *client.ProviderInfo
-	var currentModel *client.ProviderModel
+	var currentModel *client.ModelInfo
 	for _, provider := range providers {
 	for _, provider := range providers {
 		if provider.Id == appConfig.Provider {
 		if provider.Id == appConfig.Provider {
 			currentProvider = &provider
 			currentProvider = &provider
@@ -121,6 +126,18 @@ func New(ctx context.Context, version string, httpClient *client.ClientWithRespo
 	return app, nil
 	return app, nil
 }
 }
 
 
+func getDefaultModel(response *client.PostProviderListResponse, provider client.ProviderInfo) *client.ModelInfo {
+	if match, ok := response.JSON200.Default[provider.Id]; ok {
+		model := provider.Models[match]
+		return &model
+	} else {
+		for _, model := range provider.Models {
+			return &model
+		}
+	}
+	return nil
+}
+
 type Attachment struct {
 type Attachment struct {
 	FilePath string
 	FilePath string
 	FileName string
 	FileName string

+ 1 - 1
packages/tui/internal/components/chat/editor.go

@@ -284,7 +284,7 @@ func (m *editorComponent) View() string {
 
 
 	model := ""
 	model := ""
 	if m.app.Model != nil {
 	if m.app.Model != nil {
-		model = base(*m.app.Model.Name) + muted(" • /model")
+		model = base(m.app.Model.Name) + muted(" • /model")
 	}
 	}
 
 
 	space := m.width - 2 - lipgloss.Width(model) - lipgloss.Width(hint)
 	space := m.width - 2 - lipgloss.Width(model) - lipgloss.Width(hint)

+ 26 - 26
packages/tui/internal/components/chat/message.go

@@ -212,7 +212,7 @@ func renderText(message client.MessageInfo, text string, author string) string {
 func renderToolInvocation(
 func renderToolInvocation(
 	toolCall client.MessageToolInvocationToolCall,
 	toolCall client.MessageToolInvocationToolCall,
 	result *string,
 	result *string,
-	metadata map[string]any,
+	metadata client.MessageInfo_Metadata_Tool_AdditionalProperties,
 	showResult bool,
 	showResult bool,
 ) string {
 ) string {
 	ignoredTools := []string{"opencode_todoread"}
 	ignoredTools := []string{"opencode_todoread"}
@@ -264,27 +264,26 @@ func renderToolInvocation(
 		body = *result
 		body = *result
 	}
 	}
 
 
-	if metadata["error"] != nil && metadata["message"] != nil {
-		body = ""
-		error = styles.BaseStyle().
-			Foreground(t.Error()).
-			Render(metadata["message"].(string))
-		error = renderContentBlock(error, WithBorderColor(t.Error()), WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
+	if e, ok := metadata.Get("error"); ok && e.(bool) == true {
+		if m, ok := metadata.Get("message"); ok {
+			body = "" // don't show the body if there's an error
+			error = styles.BaseStyle().
+				Foreground(t.Error()).
+				Render(m.(string))
+			error = renderContentBlock(error, WithBorderColor(t.Error()), WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
+		}
 	}
 	}
 
 
 	elapsed := ""
 	elapsed := ""
-	if metadata["time"] != nil {
-		timeMap := metadata["time"].(map[string]any)
-		start := timeMap["start"].(float64)
-		end := timeMap["end"].(float64)
-		durationMs := end - start
-		duration := time.Duration(durationMs * float64(time.Millisecond))
-		roundedDuration := time.Duration(duration.Round(time.Millisecond))
-		if durationMs > 1000 {
-			roundedDuration = time.Duration(duration.Round(time.Second))
-		}
-		elapsed = styles.Muted().Render(roundedDuration.String())
+	start := metadata.Time.Start
+	end := metadata.Time.End
+	durationMs := end - start
+	duration := time.Duration(durationMs * float32(time.Millisecond))
+	roundedDuration := time.Duration(duration.Round(time.Millisecond))
+	if durationMs > 1000 {
+		roundedDuration = time.Duration(duration.Round(time.Second))
 	}
 	}
+	elapsed = styles.Muted().Render(roundedDuration.String())
 
 
 	title := ""
 	title := ""
 	switch toolCall.ToolName {
 	switch toolCall.ToolName {
@@ -292,16 +291,16 @@ func renderToolInvocation(
 		toolArgs = renderArgs(&toolArgsMap, "filePath")
 		toolArgs = renderArgs(&toolArgsMap, "filePath")
 		title = fmt.Sprintf("Read: %s   %s", toolArgs, elapsed)
 		title = fmt.Sprintf("Read: %s   %s", toolArgs, elapsed)
 		body = ""
 		body = ""
-		if metadata["preview"] != nil && toolArgsMap["filePath"] != nil {
+		if preview, ok := metadata.Get("preview"); ok && toolArgsMap["filePath"] != nil {
 			filename := toolArgsMap["filePath"].(string)
 			filename := toolArgsMap["filePath"].(string)
-			body = metadata["preview"].(string)
+			body = preview.(string)
 			body = renderFile(filename, body, WithTruncate(6))
 			body = renderFile(filename, body, WithTruncate(6))
 		}
 		}
 	case "opencode_edit":
 	case "opencode_edit":
 		filename := toolArgsMap["filePath"].(string)
 		filename := toolArgsMap["filePath"].(string)
 		title = fmt.Sprintf("Edit: %s   %s", relative(filename), elapsed)
 		title = fmt.Sprintf("Edit: %s   %s", relative(filename), elapsed)
-		if metadata["diff"] != nil {
-			patch := metadata["diff"].(string)
+		if d, ok := metadata.Get("diff"); ok {
+			patch := d.(string)
 			diffWidth := min(layout.Current.Viewport.Width, 120)
 			diffWidth := min(layout.Current.Viewport.Width, 120)
 			formattedDiff, _ := diff.FormatDiff(filename, patch, diff.WithTotalWidth(diffWidth))
 			formattedDiff, _ := diff.FormatDiff(filename, patch, diff.WithTotalWidth(diffWidth))
 			body = strings.TrimSpace(formattedDiff)
 			body = strings.TrimSpace(formattedDiff)
@@ -322,9 +321,9 @@ func renderToolInvocation(
 	case "opencode_bash":
 	case "opencode_bash":
 		description := toolArgsMap["description"].(string)
 		description := toolArgsMap["description"].(string)
 		title = fmt.Sprintf("Shell: %s   %s", description, elapsed)
 		title = fmt.Sprintf("Shell: %s   %s", description, elapsed)
-		if metadata["stdout"] != nil {
+		if stdout, ok := metadata.Get("stdout"); ok {
 			command := toolArgsMap["command"].(string)
 			command := toolArgsMap["command"].(string)
-			stdout := metadata["stdout"].(string)
+			stdout := stdout.(string)
 			body = fmt.Sprintf("```console\n> %s\n%s```", command, stdout)
 			body = fmt.Sprintf("```console\n> %s\n%s```", command, stdout)
 			body = toMarkdown(body, innerWidth, t.BackgroundSubtle())
 			body = toMarkdown(body, innerWidth, t.BackgroundSubtle())
 			body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
 			body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
@@ -339,9 +338,10 @@ func renderToolInvocation(
 		body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
 		body = renderContentBlock(body, WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
 	case "opencode_todowrite":
 	case "opencode_todowrite":
 		title = fmt.Sprintf("Planning...   %s", elapsed)
 		title = fmt.Sprintf("Planning...   %s", elapsed)
-		if finished && metadata["todos"] != nil {
+
+		if to, ok := metadata.Get("todos"); ok && finished {
 			body = ""
 			body = ""
-			todos := metadata["todos"].([]any)
+			todos := to.([]any)
 			for _, todo := range todos {
 			for _, todo := range todos {
 				t := todo.(map[string]any)
 				t := todo.(map[string]any)
 				content := t["content"].(string)
 				content := t["content"].(string)

+ 12 - 17
packages/tui/internal/components/chat/messages.go

@@ -118,7 +118,6 @@ type blockType int
 
 
 const (
 const (
 	none blockType = iota
 	none blockType = iota
-	systemTextBlock
 	userTextBlock
 	userTextBlock
 	assistantTextBlock
 	assistantTextBlock
 	toolInvocationBlock
 	toolInvocationBlock
@@ -134,10 +133,6 @@ func (m *messagesComponent) renderView() {
 	blocks := make([]string, 0)
 	blocks := make([]string, 0)
 	previousBlockType := none
 	previousBlockType := none
 	for _, message := range m.app.Messages {
 	for _, message := range m.app.Messages {
-		if message.Role == client.System {
-			continue // ignoring system messages for now
-		}
-
 		var content string
 		var content string
 		var cached bool
 		var cached bool
 
 
@@ -174,15 +169,13 @@ func (m *messagesComponent) renderView() {
 					previousBlockType = userTextBlock
 					previousBlockType = userTextBlock
 				} else if message.Role == client.Assistant {
 				} else if message.Role == client.Assistant {
 					previousBlockType = assistantTextBlock
 					previousBlockType = assistantTextBlock
-				} else if message.Role == client.System {
-					previousBlockType = systemTextBlock
 				}
 				}
 			case client.MessagePartToolInvocation:
 			case client.MessagePartToolInvocation:
 				toolInvocationPart := part.(client.MessagePartToolInvocation)
 				toolInvocationPart := part.(client.MessagePartToolInvocation)
 				toolCall, _ := toolInvocationPart.ToolInvocation.AsMessageToolInvocationToolCall()
 				toolCall, _ := toolInvocationPart.ToolInvocation.AsMessageToolInvocationToolCall()
-				metadata := map[string]any{}
+				metadata := client.MessageInfo_Metadata_Tool_AdditionalProperties{}
 				if _, ok := message.Metadata.Tool[toolCall.ToolCallId]; ok {
 				if _, ok := message.Metadata.Tool[toolCall.ToolCallId]; ok {
-					metadata = message.Metadata.Tool[toolCall.ToolCallId].(map[string]any)
+					metadata = message.Metadata.Tool[toolCall.ToolCallId]
 				}
 				}
 				var result *string
 				var result *string
 				resultPart, resultError := toolInvocationPart.ToolInvocation.AsMessageToolInvocationToolResult()
 				resultPart, resultError := toolInvocationPart.ToolInvocation.AsMessageToolInvocationToolResult()
@@ -215,14 +208,16 @@ func (m *messagesComponent) renderView() {
 		}
 		}
 
 
 		error := ""
 		error := ""
-		errorValue, _ := message.Metadata.Error.ValueByDiscriminator()
-		switch errorValue.(type) {
-		case client.UnknownError:
-			clientError := errorValue.(client.UnknownError)
-			error = clientError.Data.Message
-			error = renderContentBlock(error, WithBorderColor(t.Error()), WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
-			blocks = append(blocks, error)
-			previousBlockType = errorBlock
+		if message.Metadata.Error != nil {
+			errorValue, _ := message.Metadata.Error.ValueByDiscriminator()
+			switch errorValue.(type) {
+			case client.UnknownError:
+				clientError := errorValue.(client.UnknownError)
+				error = clientError.Data.Message
+				error = renderContentBlock(error, WithBorderColor(t.Error()), WithFullWidth(), WithPaddingTop(1), WithPaddingBottom(1))
+				blocks = append(blocks, error)
+				previousBlockType = errorBlock
+			}
 		}
 		}
 	}
 	}
 
 

+ 4 - 4
packages/tui/internal/components/dialog/models.go

@@ -125,9 +125,9 @@ func (m *modelDialog) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
 	return m, nil
 	return m, nil
 }
 }
 
 
-func (m *modelDialog) models() []client.ProviderModel {
-	models := slices.SortedFunc(maps.Values(m.provider.Models), func(a, b client.ProviderModel) int {
-		return strings.Compare(*a.Name, *b.Name)
+func (m *modelDialog) models() []client.ModelInfo {
+	models := slices.SortedFunc(maps.Values(m.provider.Models), func(a, b client.ModelInfo) int {
+		return strings.Compare(a.Name, b.Name)
 	})
 	})
 	return models
 	return models
 }
 }
@@ -205,7 +205,7 @@ func (m *modelDialog) View() string {
 				Foreground(t.BackgroundElement()).
 				Foreground(t.BackgroundElement()).
 				Bold(true)
 				Bold(true)
 		}
 		}
-		modelItems = append(modelItems, itemStyle.Render(*models[i].Name))
+		modelItems = append(modelItems, itemStyle.Render(models[i].Name))
 	}
 	}
 
 
 	scrollIndicator := m.getScrollIndicators(maxDialogWidth)
 	scrollIndicator := m.getScrollIndicators(maxDialogWidth)

+ 1 - 3
packages/tui/internal/state/state.go

@@ -7,7 +7,7 @@ import (
 type SessionSelectedMsg = *client.SessionInfo
 type SessionSelectedMsg = *client.SessionInfo
 type ModelSelectedMsg struct {
 type ModelSelectedMsg struct {
 	Provider client.ProviderInfo
 	Provider client.ProviderInfo
-	Model    client.ProviderModel
+	Model    client.ModelInfo
 }
 }
 
 
 type SessionClearedMsg struct{}
 type SessionClearedMsg struct{}
@@ -17,5 +17,3 @@ type CompactSessionMsg struct{}
 type StateUpdatedMsg struct {
 type StateUpdatedMsg struct {
 	State map[string]any
 	State map[string]any
 }
 }
-
-// TODO: store in CONFIG/tui.yaml

+ 130 - 21
packages/tui/pkg/client/gen/openapi.json

@@ -439,6 +439,45 @@
         "parameters": [],
         "parameters": [],
         "description": "List all providers"
         "description": "List all providers"
       }
       }
+    },
+    "/file_search": {
+      "post": {
+        "responses": {
+          "200": {
+            "description": "Search for files",
+            "content": {
+              "application/json": {
+                "schema": {
+                  "type": "array",
+                  "items": {
+                    "type": "string"
+                  }
+                }
+              }
+            }
+          }
+        },
+        "operationId": "postFile_search",
+        "parameters": [],
+        "description": "Search for files",
+        "requestBody": {
+          "content": {
+            "application/json": {
+              "schema": {
+                "type": "object",
+                "properties": {
+                  "query": {
+                    "type": "string"
+                  }
+                },
+                "required": [
+                  "query"
+                ]
+              }
+            }
+          }
+        }
+      }
     }
     }
   },
   },
   "components": {
   "components": {
@@ -618,7 +657,6 @@
           "role": {
           "role": {
             "type": "string",
             "type": "string",
             "enum": [
             "enum": [
-              "system",
               "user",
               "user",
               "assistant"
               "assistant"
             ]
             ]
@@ -668,17 +706,65 @@
               },
               },
               "tool": {
               "tool": {
                 "type": "object",
                 "type": "object",
-                "additionalProperties": {}
+                "additionalProperties": {
+                  "type": "object",
+                  "properties": {
+                    "title": {
+                      "type": "string"
+                    },
+                    "time": {
+                      "type": "object",
+                      "properties": {
+                        "start": {
+                          "type": "number"
+                        },
+                        "end": {
+                          "type": "number"
+                        }
+                      },
+                      "required": [
+                        "start",
+                        "end"
+                      ]
+                    }
+                  },
+                  "required": [
+                    "title",
+                    "time"
+                  ],
+                  "additionalProperties": {}
+                }
               },
               },
               "assistant": {
               "assistant": {
                 "type": "object",
                 "type": "object",
                 "properties": {
                 "properties": {
+                  "system": {
+                    "type": "array",
+                    "items": {
+                      "type": "string"
+                    }
+                  },
                   "modelID": {
                   "modelID": {
                     "type": "string"
                     "type": "string"
                   },
                   },
                   "providerID": {
                   "providerID": {
                     "type": "string"
                     "type": "string"
                   },
                   },
+                  "path": {
+                    "type": "object",
+                    "properties": {
+                      "cwd": {
+                        "type": "string"
+                      },
+                      "root": {
+                        "type": "string"
+                      }
+                    },
+                    "required": [
+                      "cwd",
+                      "root"
+                    ]
+                  },
                   "cost": {
                   "cost": {
                     "type": "number"
                     "type": "number"
                   },
                   },
@@ -706,8 +792,10 @@
                   }
                   }
                 },
                 },
                 "required": [
                 "required": [
+                  "system",
                   "modelID",
                   "modelID",
                   "providerID",
                   "providerID",
+                  "path",
                   "cost",
                   "cost",
                   "tokens"
                   "tokens"
                 ]
                 ]
@@ -715,7 +803,6 @@
             },
             },
             "required": [
             "required": [
               "time",
               "time",
-              "error",
               "sessionID",
               "sessionID",
               "tool"
               "tool"
             ]
             ]
@@ -1036,10 +1123,18 @@
             "properties": {
             "properties": {
               "part": {
               "part": {
                 "$ref": "#/components/schemas/Message.Part"
                 "$ref": "#/components/schemas/Message.Part"
+              },
+              "sessionID": {
+                "type": "string"
+              },
+              "messageID": {
+                "type": "string"
               }
               }
             },
             },
             "required": [
             "required": [
-              "part"
+              "part",
+              "sessionID",
+              "messageID"
             ]
             ]
           }
           }
         },
         },
@@ -1079,6 +1174,10 @@
             "type": "string",
             "type": "string",
             "pattern": "^ses"
             "pattern": "^ses"
           },
           },
+          "parentID": {
+            "type": "string",
+            "pattern": "^ses"
+          },
           "share": {
           "share": {
             "type": "object",
             "type": "object",
             "properties": {
             "properties": {
@@ -1146,10 +1245,7 @@
                   }
                   }
                 }
                 }
               }
               }
-            },
-            "required": [
-              "error"
-            ]
+            }
           }
           }
         },
         },
         "required": [
         "required": [
@@ -1220,31 +1316,35 @@
       "Provider.Info": {
       "Provider.Info": {
         "type": "object",
         "type": "object",
         "properties": {
         "properties": {
-          "id": {
+          "name": {
             "type": "string"
             "type": "string"
           },
           },
-          "name": {
+          "env": {
+            "type": "array",
+            "items": {
+              "type": "string"
+            }
+          },
+          "id": {
             "type": "string"
             "type": "string"
           },
           },
           "models": {
           "models": {
             "type": "object",
             "type": "object",
             "additionalProperties": {
             "additionalProperties": {
-              "$ref": "#/components/schemas/Provider.Model"
+              "$ref": "#/components/schemas/Model.Info"
             }
             }
           }
           }
         },
         },
         "required": [
         "required": [
-          "id",
           "name",
           "name",
+          "env",
+          "id",
           "models"
           "models"
         ]
         ]
       },
       },
-      "Provider.Model": {
+      "Model.Info": {
         "type": "object",
         "type": "object",
         "properties": {
         "properties": {
-          "id": {
-            "type": "string"
-          },
           "name": {
           "name": {
             "type": "string"
             "type": "string"
           },
           },
@@ -1254,16 +1354,19 @@
           "reasoning": {
           "reasoning": {
             "type": "boolean"
             "type": "boolean"
           },
           },
+          "temperature": {
+            "type": "boolean"
+          },
           "cost": {
           "cost": {
             "type": "object",
             "type": "object",
             "properties": {
             "properties": {
               "input": {
               "input": {
                 "type": "number"
                 "type": "number"
               },
               },
-              "inputCached": {
+              "output": {
                 "type": "number"
                 "type": "number"
               },
               },
-              "output": {
+              "inputCached": {
                 "type": "number"
                 "type": "number"
               },
               },
               "outputCached": {
               "outputCached": {
@@ -1272,8 +1375,8 @@
             },
             },
             "required": [
             "required": [
               "input",
               "input",
-              "inputCached",
               "output",
               "output",
+              "inputCached",
               "outputCached"
               "outputCached"
             ]
             ]
           },
           },
@@ -1291,13 +1394,19 @@
               "context",
               "context",
               "output"
               "output"
             ]
             ]
+          },
+          "id": {
+            "type": "string"
           }
           }
         },
         },
         "required": [
         "required": [
-          "id",
+          "name",
           "attachment",
           "attachment",
+          "reasoning",
+          "temperature",
           "cost",
           "cost",
-          "limit"
+          "limit",
+          "id"
         ]
         ]
       }
       }
     }
     }

+ 268 - 23
packages/tui/pkg/client/generated-client.go

@@ -20,7 +20,6 @@ import (
 // Defines values for MessageInfoRole.
 // Defines values for MessageInfoRole.
 const (
 const (
 	Assistant MessageInfoRole = "assistant"
 	Assistant MessageInfoRole = "assistant"
-	System    MessageInfoRole = "system"
 	User      MessageInfoRole = "user"
 	User      MessageInfoRole = "user"
 )
 )
 
 
@@ -61,7 +60,9 @@ type EventLspClientDiagnostics struct {
 // EventMessagePartUpdated defines model for Event.message.part.updated.
 // EventMessagePartUpdated defines model for Event.message.part.updated.
 type EventMessagePartUpdated struct {
 type EventMessagePartUpdated struct {
 	Properties struct {
 	Properties struct {
-		Part MessagePart `json:"part"`
+		MessageID string      `json:"messageID"`
+		Part      MessagePart `json:"part"`
+		SessionID string      `json:"sessionID"`
 	} `json:"properties"`
 	} `json:"properties"`
 	Type string `json:"type"`
 	Type string `json:"type"`
 }
 }
@@ -83,7 +84,7 @@ type EventPermissionUpdated struct {
 // EventSessionError defines model for Event.session.error.
 // EventSessionError defines model for Event.session.error.
 type EventSessionError struct {
 type EventSessionError struct {
 	Properties struct {
 	Properties struct {
-		Error EventSessionError_Properties_Error `json:"error"`
+		Error *EventSessionError_Properties_Error `json:"error,omitempty"`
 	} `json:"properties"`
 	} `json:"properties"`
 	Type string `json:"type"`
 	Type string `json:"type"`
 }
 }
@@ -115,23 +116,28 @@ type MessageInfo struct {
 	Id       string `json:"id"`
 	Id       string `json:"id"`
 	Metadata struct {
 	Metadata struct {
 		Assistant *struct {
 		Assistant *struct {
-			Cost       float32 `json:"cost"`
-			ModelID    string  `json:"modelID"`
-			ProviderID string  `json:"providerID"`
-			Summary    *bool   `json:"summary,omitempty"`
+			Cost    float32 `json:"cost"`
+			ModelID string  `json:"modelID"`
+			Path    struct {
+				Cwd  string `json:"cwd"`
+				Root string `json:"root"`
+			} `json:"path"`
+			ProviderID string   `json:"providerID"`
+			Summary    *bool    `json:"summary,omitempty"`
+			System     []string `json:"system"`
 			Tokens     struct {
 			Tokens     struct {
 				Input     float32 `json:"input"`
 				Input     float32 `json:"input"`
 				Output    float32 `json:"output"`
 				Output    float32 `json:"output"`
 				Reasoning float32 `json:"reasoning"`
 				Reasoning float32 `json:"reasoning"`
 			} `json:"tokens"`
 			} `json:"tokens"`
 		} `json:"assistant,omitempty"`
 		} `json:"assistant,omitempty"`
-		Error     MessageInfo_Metadata_Error `json:"error"`
-		SessionID string                     `json:"sessionID"`
+		Error     *MessageInfo_Metadata_Error `json:"error,omitempty"`
+		SessionID string                      `json:"sessionID"`
 		Time      struct {
 		Time      struct {
 			Completed *float32 `json:"completed,omitempty"`
 			Completed *float32 `json:"completed,omitempty"`
 			Created   float32  `json:"created"`
 			Created   float32  `json:"created"`
 		} `json:"time"`
 		} `json:"time"`
-		Tool map[string]interface{} `json:"tool"`
+		Tool map[string]MessageInfo_Metadata_Tool_AdditionalProperties `json:"tool"`
 	} `json:"metadata"`
 	} `json:"metadata"`
 	Parts []MessagePart   `json:"parts"`
 	Parts []MessagePart   `json:"parts"`
 	Role  MessageInfoRole `json:"role"`
 	Role  MessageInfoRole `json:"role"`
@@ -142,6 +148,16 @@ type MessageInfo_Metadata_Error struct {
 	union json.RawMessage
 	union json.RawMessage
 }
 }
 
 
+// MessageInfo_Metadata_Tool_AdditionalProperties defines model for MessageInfo.Metadata.Tool.AdditionalProperties.
+type MessageInfo_Metadata_Tool_AdditionalProperties struct {
+	Time struct {
+		End   float32 `json:"end"`
+		Start float32 `json:"start"`
+	} `json:"time"`
+	Title                string                 `json:"title"`
+	AdditionalProperties map[string]interface{} `json:"-"`
+}
+
 // MessageInfoRole defines model for MessageInfo.Role.
 // MessageInfoRole defines model for MessageInfo.Role.
 type MessageInfoRole string
 type MessageInfoRole string
 
 
@@ -224,15 +240,8 @@ type MessageToolInvocationToolResult struct {
 	ToolName   string       `json:"toolName"`
 	ToolName   string       `json:"toolName"`
 }
 }
 
 
-// ProviderInfo defines model for Provider.Info.
-type ProviderInfo struct {
-	Id     string                   `json:"id"`
-	Models map[string]ProviderModel `json:"models"`
-	Name   string                   `json:"name"`
-}
-
-// ProviderModel defines model for Provider.Model.
-type ProviderModel struct {
+// ModelInfo defines model for Model.Info.
+type ModelInfo struct {
 	Attachment bool `json:"attachment"`
 	Attachment bool `json:"attachment"`
 	Cost       struct {
 	Cost       struct {
 		Input        float32 `json:"input"`
 		Input        float32 `json:"input"`
@@ -245,8 +254,17 @@ type ProviderModel struct {
 		Context float32 `json:"context"`
 		Context float32 `json:"context"`
 		Output  float32 `json:"output"`
 		Output  float32 `json:"output"`
 	} `json:"limit"`
 	} `json:"limit"`
-	Name      *string `json:"name,omitempty"`
-	Reasoning *bool   `json:"reasoning,omitempty"`
+	Name        string `json:"name"`
+	Reasoning   bool   `json:"reasoning"`
+	Temperature bool   `json:"temperature"`
+}
+
+// ProviderInfo defines model for Provider.Info.
+type ProviderInfo struct {
+	Env    []string             `json:"env"`
+	Id     string               `json:"id"`
+	Models map[string]ModelInfo `json:"models"`
+	Name   string               `json:"name"`
 }
 }
 
 
 // ProviderAuthError defines model for ProviderAuthError.
 // ProviderAuthError defines model for ProviderAuthError.
@@ -279,8 +297,9 @@ type PermissionInfo struct {
 
 
 // SessionInfo defines model for session.info.
 // SessionInfo defines model for session.info.
 type SessionInfo struct {
 type SessionInfo struct {
-	Id    string `json:"id"`
-	Share *struct {
+	Id       string  `json:"id"`
+	ParentID *string `json:"parentID,omitempty"`
+	Share    *struct {
 		Secret string `json:"secret"`
 		Secret string `json:"secret"`
 		Url    string `json:"url"`
 		Url    string `json:"url"`
 	} `json:"share,omitempty"`
 	} `json:"share,omitempty"`
@@ -291,6 +310,11 @@ type SessionInfo struct {
 	Title string `json:"title"`
 	Title string `json:"title"`
 }
 }
 
 
+// PostFileSearchJSONBody defines parameters for PostFileSearch.
+type PostFileSearchJSONBody struct {
+	Query string `json:"query"`
+}
+
 // PostSessionAbortJSONBody defines parameters for PostSessionAbort.
 // PostSessionAbortJSONBody defines parameters for PostSessionAbort.
 type PostSessionAbortJSONBody struct {
 type PostSessionAbortJSONBody struct {
 	SessionID string `json:"sessionID"`
 	SessionID string `json:"sessionID"`
@@ -328,6 +352,9 @@ type PostSessionSummarizeJSONBody struct {
 	SessionID  string `json:"sessionID"`
 	SessionID  string `json:"sessionID"`
 }
 }
 
 
+// PostFileSearchJSONRequestBody defines body for PostFileSearch for application/json ContentType.
+type PostFileSearchJSONRequestBody PostFileSearchJSONBody
+
 // PostSessionAbortJSONRequestBody defines body for PostSessionAbort for application/json ContentType.
 // PostSessionAbortJSONRequestBody defines body for PostSessionAbort for application/json ContentType.
 type PostSessionAbortJSONRequestBody PostSessionAbortJSONBody
 type PostSessionAbortJSONRequestBody PostSessionAbortJSONBody
 
 
@@ -346,6 +373,85 @@ type PostSessionShareJSONRequestBody PostSessionShareJSONBody
 // PostSessionSummarizeJSONRequestBody defines body for PostSessionSummarize for application/json ContentType.
 // PostSessionSummarizeJSONRequestBody defines body for PostSessionSummarize for application/json ContentType.
 type PostSessionSummarizeJSONRequestBody PostSessionSummarizeJSONBody
 type PostSessionSummarizeJSONRequestBody PostSessionSummarizeJSONBody
 
 
+// Getter for additional properties for MessageInfo_Metadata_Tool_AdditionalProperties. Returns the specified
+// element and whether it was found
+func (a MessageInfo_Metadata_Tool_AdditionalProperties) Get(fieldName string) (value interface{}, found bool) {
+	if a.AdditionalProperties != nil {
+		value, found = a.AdditionalProperties[fieldName]
+	}
+	return
+}
+
+// Setter for additional properties for MessageInfo_Metadata_Tool_AdditionalProperties
+func (a *MessageInfo_Metadata_Tool_AdditionalProperties) Set(fieldName string, value interface{}) {
+	if a.AdditionalProperties == nil {
+		a.AdditionalProperties = make(map[string]interface{})
+	}
+	a.AdditionalProperties[fieldName] = value
+}
+
+// Override default JSON handling for MessageInfo_Metadata_Tool_AdditionalProperties to handle AdditionalProperties
+func (a *MessageInfo_Metadata_Tool_AdditionalProperties) UnmarshalJSON(b []byte) error {
+	object := make(map[string]json.RawMessage)
+	err := json.Unmarshal(b, &object)
+	if err != nil {
+		return err
+	}
+
+	if raw, found := object["time"]; found {
+		err = json.Unmarshal(raw, &a.Time)
+		if err != nil {
+			return fmt.Errorf("error reading 'time': %w", err)
+		}
+		delete(object, "time")
+	}
+
+	if raw, found := object["title"]; found {
+		err = json.Unmarshal(raw, &a.Title)
+		if err != nil {
+			return fmt.Errorf("error reading 'title': %w", err)
+		}
+		delete(object, "title")
+	}
+
+	if len(object) != 0 {
+		a.AdditionalProperties = make(map[string]interface{})
+		for fieldName, fieldBuf := range object {
+			var fieldVal interface{}
+			err := json.Unmarshal(fieldBuf, &fieldVal)
+			if err != nil {
+				return fmt.Errorf("error unmarshaling field %s: %w", fieldName, err)
+			}
+			a.AdditionalProperties[fieldName] = fieldVal
+		}
+	}
+	return nil
+}
+
+// Override default JSON handling for MessageInfo_Metadata_Tool_AdditionalProperties to handle AdditionalProperties
+func (a MessageInfo_Metadata_Tool_AdditionalProperties) MarshalJSON() ([]byte, error) {
+	var err error
+	object := make(map[string]json.RawMessage)
+
+	object["time"], err = json.Marshal(a.Time)
+	if err != nil {
+		return nil, fmt.Errorf("error marshaling 'time': %w", err)
+	}
+
+	object["title"], err = json.Marshal(a.Title)
+	if err != nil {
+		return nil, fmt.Errorf("error marshaling 'title': %w", err)
+	}
+
+	for fieldName, field := range a.AdditionalProperties {
+		object[fieldName], err = json.Marshal(field)
+		if err != nil {
+			return nil, fmt.Errorf("error marshaling '%s': %w", fieldName, err)
+		}
+	}
+	return json.Marshal(object)
+}
+
 // AsEventStorageWrite returns the union data inside the Event as a EventStorageWrite
 // AsEventStorageWrite returns the union data inside the Event as a EventStorageWrite
 func (t Event) AsEventStorageWrite() (EventStorageWrite, error) {
 func (t Event) AsEventStorageWrite() (EventStorageWrite, error) {
 	var body EventStorageWrite
 	var body EventStorageWrite
@@ -1173,6 +1279,11 @@ type ClientInterface interface {
 	// GetEvent request
 	// GetEvent request
 	GetEvent(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
 	GetEvent(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
 
 
+	// PostFileSearchWithBody request with any body
+	PostFileSearchWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
+
+	PostFileSearch(ctx context.Context, body PostFileSearchJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
+
 	// PostPathGet request
 	// PostPathGet request
 	PostPathGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
 	PostPathGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error)
 
 
@@ -1252,6 +1363,30 @@ func (c *Client) GetEvent(ctx context.Context, reqEditors ...RequestEditorFn) (*
 	return c.Client.Do(req)
 	return c.Client.Do(req)
 }
 }
 
 
+func (c *Client) PostFileSearchWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
+	req, err := NewPostFileSearchRequestWithBody(c.Server, contentType, body)
+	if err != nil {
+		return nil, err
+	}
+	req = req.WithContext(ctx)
+	if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+		return nil, err
+	}
+	return c.Client.Do(req)
+}
+
+func (c *Client) PostFileSearch(ctx context.Context, body PostFileSearchJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
+	req, err := NewPostFileSearchRequest(c.Server, body)
+	if err != nil {
+		return nil, err
+	}
+	req = req.WithContext(ctx)
+	if err := c.applyEditors(ctx, req, reqEditors); err != nil {
+		return nil, err
+	}
+	return c.Client.Do(req)
+}
+
 func (c *Client) PostPathGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
 func (c *Client) PostPathGet(ctx context.Context, reqEditors ...RequestEditorFn) (*http.Response, error) {
 	req, err := NewPostPathGetRequest(c.Server)
 	req, err := NewPostPathGetRequest(c.Server)
 	if err != nil {
 	if err != nil {
@@ -1525,6 +1660,46 @@ func NewGetEventRequest(server string) (*http.Request, error) {
 	return req, nil
 	return req, nil
 }
 }
 
 
+// NewPostFileSearchRequest calls the generic PostFileSearch builder with application/json body
+func NewPostFileSearchRequest(server string, body PostFileSearchJSONRequestBody) (*http.Request, error) {
+	var bodyReader io.Reader
+	buf, err := json.Marshal(body)
+	if err != nil {
+		return nil, err
+	}
+	bodyReader = bytes.NewReader(buf)
+	return NewPostFileSearchRequestWithBody(server, "application/json", bodyReader)
+}
+
+// NewPostFileSearchRequestWithBody generates requests for PostFileSearch with any type of body
+func NewPostFileSearchRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
+	var err error
+
+	serverURL, err := url.Parse(server)
+	if err != nil {
+		return nil, err
+	}
+
+	operationPath := fmt.Sprintf("/file_search")
+	if operationPath[0] == '/' {
+		operationPath = "." + operationPath
+	}
+
+	queryURL, err := serverURL.Parse(operationPath)
+	if err != nil {
+		return nil, err
+	}
+
+	req, err := http.NewRequest("POST", queryURL.String(), body)
+	if err != nil {
+		return nil, err
+	}
+
+	req.Header.Add("Content-Type", contentType)
+
+	return req, nil
+}
+
 // NewPostPathGetRequest generates requests for PostPathGet
 // NewPostPathGetRequest generates requests for PostPathGet
 func NewPostPathGetRequest(server string) (*http.Request, error) {
 func NewPostPathGetRequest(server string) (*http.Request, error) {
 	var err error
 	var err error
@@ -1925,6 +2100,11 @@ type ClientWithResponsesInterface interface {
 	// GetEventWithResponse request
 	// GetEventWithResponse request
 	GetEventWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetEventResponse, error)
 	GetEventWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*GetEventResponse, error)
 
 
+	// PostFileSearchWithBodyWithResponse request with any body
+	PostFileSearchWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostFileSearchResponse, error)
+
+	PostFileSearchWithResponse(ctx context.Context, body PostFileSearchJSONRequestBody, reqEditors ...RequestEditorFn) (*PostFileSearchResponse, error)
+
 	// PostPathGetWithResponse request
 	// PostPathGetWithResponse request
 	PostPathGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*PostPathGetResponse, error)
 	PostPathGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*PostPathGetResponse, error)
 
 
@@ -2034,6 +2214,28 @@ func (r GetEventResponse) StatusCode() int {
 	return 0
 	return 0
 }
 }
 
 
+type PostFileSearchResponse struct {
+	Body         []byte
+	HTTPResponse *http.Response
+	JSON200      *[]string
+}
+
+// Status returns HTTPResponse.Status
+func (r PostFileSearchResponse) Status() string {
+	if r.HTTPResponse != nil {
+		return r.HTTPResponse.Status
+	}
+	return http.StatusText(0)
+}
+
+// StatusCode returns HTTPResponse.StatusCode
+func (r PostFileSearchResponse) StatusCode() int {
+	if r.HTTPResponse != nil {
+		return r.HTTPResponse.StatusCode
+	}
+	return 0
+}
+
 type PostPathGetResponse struct {
 type PostPathGetResponse struct {
 	Body         []byte
 	Body         []byte
 	HTTPResponse *http.Response
 	HTTPResponse *http.Response
@@ -2290,6 +2492,23 @@ func (c *ClientWithResponses) GetEventWithResponse(ctx context.Context, reqEdito
 	return ParseGetEventResponse(rsp)
 	return ParseGetEventResponse(rsp)
 }
 }
 
 
+// PostFileSearchWithBodyWithResponse request with arbitrary body returning *PostFileSearchResponse
+func (c *ClientWithResponses) PostFileSearchWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*PostFileSearchResponse, error) {
+	rsp, err := c.PostFileSearchWithBody(ctx, contentType, body, reqEditors...)
+	if err != nil {
+		return nil, err
+	}
+	return ParsePostFileSearchResponse(rsp)
+}
+
+func (c *ClientWithResponses) PostFileSearchWithResponse(ctx context.Context, body PostFileSearchJSONRequestBody, reqEditors ...RequestEditorFn) (*PostFileSearchResponse, error) {
+	rsp, err := c.PostFileSearch(ctx, body, reqEditors...)
+	if err != nil {
+		return nil, err
+	}
+	return ParsePostFileSearchResponse(rsp)
+}
+
 // PostPathGetWithResponse request returning *PostPathGetResponse
 // PostPathGetWithResponse request returning *PostPathGetResponse
 func (c *ClientWithResponses) PostPathGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*PostPathGetResponse, error) {
 func (c *ClientWithResponses) PostPathGetWithResponse(ctx context.Context, reqEditors ...RequestEditorFn) (*PostPathGetResponse, error) {
 	rsp, err := c.PostPathGet(ctx, reqEditors...)
 	rsp, err := c.PostPathGet(ctx, reqEditors...)
@@ -2506,6 +2725,32 @@ func ParseGetEventResponse(rsp *http.Response) (*GetEventResponse, error) {
 	return response, nil
 	return response, nil
 }
 }
 
 
+// ParsePostFileSearchResponse parses an HTTP response from a PostFileSearchWithResponse call
+func ParsePostFileSearchResponse(rsp *http.Response) (*PostFileSearchResponse, error) {
+	bodyBytes, err := io.ReadAll(rsp.Body)
+	defer func() { _ = rsp.Body.Close() }()
+	if err != nil {
+		return nil, err
+	}
+
+	response := &PostFileSearchResponse{
+		Body:         bodyBytes,
+		HTTPResponse: rsp,
+	}
+
+	switch {
+	case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
+		var dest []string
+		if err := json.Unmarshal(bodyBytes, &dest); err != nil {
+			return nil, err
+		}
+		response.JSON200 = &dest
+
+	}
+
+	return response, nil
+}
+
 // ParsePostPathGetResponse parses an HTTP response from a PostPathGetWithResponse call
 // ParsePostPathGetResponse parses an HTTP response from a PostPathGetWithResponse call
 func ParsePostPathGetResponse(rsp *http.Response) (*PostPathGetResponse, error) {
 func ParsePostPathGetResponse(rsp *http.Response) (*PostPathGetResponse, error) {
 	bodyBytes, err := io.ReadAll(rsp.Body)
 	bodyBytes, err := io.ReadAll(rsp.Body)