Ctrl K
ComunidadGuías…

pluginapi/completion_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package pluginapi

import (
	"testing"

	"github.com/stretchr/testify/assert"
	"github.com/stretchr/testify/require"
)

func sampleCompletion() *Completion {
	c := &Completion{Choices: []Choice{
		{Index: 0, FinishReason: "stop", Message: Message{Role: RoleAssistant, Parts: []Part{
			{Kind: PartReasoning, Text: "thinking"},
			{Kind: PartText, Text: "hello "},
			{Kind: PartText, Text: "world"},
			{Kind: PartToolCall, ToolCall: &ToolCall{ID: "c1", Name: "f"}},
		}}},
		{Index: 1, FinishReason: "stop", Message: TextMessage(RoleAssistant, "second")},
	}}
	c.Reset()
	return c
}

func TestCompletionText(t *testing.T) {
	c := sampleCompletion()
	got := c.Text(0)
	assert.Equal(t, "hello world", got)
	got = c.Text(7)
	assert.Empty(t, got)
}

func TestCompletionEdits(t *testing.T) {
	tests := []struct {
		name    string
		edit    func(c *Completion) error
		wantErr bool
		wantKey string
		want    ChangeKind
		check   func(t *testing.T, c *Completion)
	}{
		{
			name:    "set text",
			edit:    func(c *Completion) error { return c.SetText(0, 1, "bye ") },
			wantKey: "choice:0", want: ChangeEdited,
			check: func(t *testing.T, c *Completion) {
				assert.Equal(t, "bye world", c.Text(0))

			},
		},
		{name: "set text on reasoning part", edit: func(c *Completion) error { return c.SetText(0, 0, "x") }, wantErr: true},
		{name: "set text bad choice", edit: func(c *Completion) error { return c.SetText(5, 0, "x") }, wantErr: true},
		{name: "set text bad part", edit: func(c *Completion) error { return c.SetText(1, 3, "x") }, wantErr: true},
		{
			name:    "finish reason",
			edit:    func(c *Completion) error { return c.SetFinishReason(1, "content_filter") },
			wantKey: "choice:1", want: ChangeEdited,
			check: func(t *testing.T, c *Completion) {
				assert.Equal(t, "content_filter", c.Choices[1].FinishReason)

			},
		},
		{name: "finish reason bad choice", edit: func(c *Completion) error { return c.SetFinishReason(9, "stop") }, wantErr: true},
		{
			name:    "replace text keeps non-text parts",
			edit:    func(c *Completion) error { return c.ReplaceText(0, "[redacted]") },
			wantKey: "choice:0", want: ChangeReplaced,
			check: func(t *testing.T, c *Completion) {
				parts := c.Choices[0].Message.Parts
				require.Len(t, parts, 3)
				assert.Equal(t, PartReasoning, parts[0].Kind)
				assert.Equal(t, "[redacted]", parts[1].Text)
				assert.Equal(t, PartToolCall, parts[2].Kind)

			},
		},
		{
			name: "replace text with no text parts prepends",
			edit: func(c *Completion) error {
				c.Choices[1].Message.Parts = []Part{{Kind: PartToolCall, ToolCall: &ToolCall{ID: "z"}}}
				return c.ReplaceText(1, "answer")
			},
			wantKey: "choice:1", want: ChangeReplaced,
			check: func(t *testing.T, c *Completion) {
				parts := c.Choices[1].Message.Parts
				require.Len(t, parts, 2)
				assert.Equal(t, "answer", parts[0].Text)
				assert.Equal(t, PartToolCall, parts[1].Kind)

			},
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := sampleCompletion()
			err := tt.edit(c)
			if tt.wantErr {
				require.Error(t, err)
				assert.False(t, c.Changes().Dirty)

				return
			}
			require.NoError(t, err)

			ch := c.Changes()
			assert.True(t, ch.Dirty)
			assert.Equal(t, tt.want, ch.Messages[tt.wantKey], "changes = %+v", ch)

			tt.check(t, c)
		})
	}
}

func TestCompletionReplaceThenEditStaysReplaced(t *testing.T) {
	c := sampleCompletion()
	err := c.ReplaceText(0, "a")
	require.NoError(t, err)
	err = c.SetText(0, 1, "b")
	require.NoError(t, err)
	assert.Equal(t, ChangeReplaced, c.Changes().Messages["choice:0"])

	c.Reset()
	assert.False(t, c.Changes().Dirty)
}