Private
Public Access
1
0

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:
2024-06-12 08:35:07 +00:00
parent 85a2abbbf3
commit 3fde58b77d
35 changed files with 608 additions and 749 deletions

View File

@@ -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")