Package restructure and API changes, several fixes
- More emphasis on `api` package. It now holds database model structs from `lmcli/models` (which is now gone) as well as the tool spec, call, and result types. `tools.Tool` is now `api.ToolSpec`. `api.ChatCompletionClient` was renamed to `api.ChatCompletionProvider`. - Change ChatCompletion interface and implementations to no longer do automatic tool call recursion - they simply return a ToolCall message which the caller can decide what to do with (e.g. prompt for user confirmation before executing) - `api.ChatCompletionProvider` functions have had their ReplyCallback parameter removed, as now they only return a single reply. - Added a top-level `agent` package, moved the current built-in tools implementations under `agent/toolbox`. `tools.ExecuteToolCalls` is now `agent.ExecuteToolCalls`. - Fixed request context handling in openai, google, ollama (use `NewRequestWithContext`), cleaned up request cancellation in TUI - Fix tool call tui persistence bug (we were skipping message with empty content) - Now handle tool calling from TUI layer TODO: - Prompt users before executing tool calls - Automatically send tool results to the model (or make this toggleable)
This commit is contained in:
@@ -5,7 +5,7 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
models "git.mlow.ca/mlow/lmcli/pkg/lmcli/model"
|
||||
"git.mlow.ca/mlow/lmcli/pkg/api"
|
||||
"git.mlow.ca/mlow/lmcli/pkg/tui/styles"
|
||||
tuiutil "git.mlow.ca/mlow/lmcli/pkg/tui/util"
|
||||
"github.com/charmbracelet/lipgloss"
|
||||
@@ -63,22 +63,22 @@ func (m Model) View() string {
|
||||
return lipgloss.JoinVertical(lipgloss.Left, sections...)
|
||||
}
|
||||
|
||||
func (m *Model) renderMessageHeading(i int, message *models.Message) string {
|
||||
func (m *Model) renderMessageHeading(i int, message *api.Message) string {
|
||||
icon := ""
|
||||
friendly := message.Role.FriendlyRole()
|
||||
style := lipgloss.NewStyle().Faint(true).Bold(true)
|
||||
|
||||
switch message.Role {
|
||||
case models.MessageRoleSystem:
|
||||
case api.MessageRoleSystem:
|
||||
icon = "⚙️"
|
||||
case models.MessageRoleUser:
|
||||
case api.MessageRoleUser:
|
||||
style = userStyle
|
||||
case models.MessageRoleAssistant:
|
||||
case api.MessageRoleAssistant:
|
||||
style = assistantStyle
|
||||
case models.MessageRoleToolCall:
|
||||
case api.MessageRoleToolCall:
|
||||
style = assistantStyle
|
||||
friendly = models.MessageRoleAssistant.FriendlyRole()
|
||||
case models.MessageRoleToolResult:
|
||||
friendly = api.MessageRoleAssistant.FriendlyRole()
|
||||
case api.MessageRoleToolResult:
|
||||
icon = "🔧"
|
||||
}
|
||||
|
||||
@@ -139,21 +139,21 @@ func (m *Model) renderMessage(i int) string {
|
||||
}
|
||||
|
||||
// Show the assistant's cursor
|
||||
if m.state == pendingResponse && i == len(m.messages)-1 && msg.Role == models.MessageRoleAssistant {
|
||||
if m.state == pendingResponse && i == len(m.messages)-1 && msg.Role == api.MessageRoleAssistant {
|
||||
sb.WriteString(m.replyCursor.View())
|
||||
}
|
||||
|
||||
// Write tool call info
|
||||
var toolString string
|
||||
switch msg.Role {
|
||||
case models.MessageRoleToolCall:
|
||||
case api.MessageRoleToolCall:
|
||||
bytes, err := yaml.Marshal(msg.ToolCalls)
|
||||
if err != nil {
|
||||
toolString = "Could not serialize ToolCalls"
|
||||
} else {
|
||||
toolString = "tool_calls:\n" + string(bytes)
|
||||
}
|
||||
case models.MessageRoleToolResult:
|
||||
case api.MessageRoleToolResult:
|
||||
if !m.showToolResults {
|
||||
break
|
||||
}
|
||||
@@ -221,11 +221,11 @@ func (m *Model) conversationMessagesView() string {
|
||||
m.messageOffsets[i] = lineCnt
|
||||
|
||||
switch message.Role {
|
||||
case models.MessageRoleToolCall:
|
||||
case api.MessageRoleToolCall:
|
||||
if !m.showToolResults && message.Content == "" {
|
||||
continue
|
||||
}
|
||||
case models.MessageRoleToolResult:
|
||||
case api.MessageRoleToolResult:
|
||||
if !m.showToolResults {
|
||||
continue
|
||||
}
|
||||
@@ -251,9 +251,9 @@ func (m *Model) conversationMessagesView() string {
|
||||
}
|
||||
|
||||
// Render a placeholder for the incoming assistant reply
|
||||
if m.state == pendingResponse && (len(m.messages) == 0 || m.messages[len(m.messages)-1].Role != models.MessageRoleAssistant) {
|
||||
heading := m.renderMessageHeading(-1, &models.Message{
|
||||
Role: models.MessageRoleAssistant,
|
||||
if m.state == pendingResponse && (len(m.messages) == 0 || m.messages[len(m.messages)-1].Role != api.MessageRoleAssistant) {
|
||||
heading := m.renderMessageHeading(-1, &api.Message{
|
||||
Role: api.MessageRoleAssistant,
|
||||
})
|
||||
sb.WriteString(heading)
|
||||
sb.WriteString("\n")
|
||||
|
||||
Reference in New Issue
Block a user