Ctrl K
ComunidadGuías…

pluginapi/message.go

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

Archivo original ↗Preguntar a KiBot
package pluginapi

import (
	"encoding/json"
	"strings"
)

// Role is the author of a [Message].
type Role string

const (
	RoleSystem    Role = "system"
	RoleDeveloper Role = "developer"
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
	// RoleTool marks a tool result message (chat "tool" role, Responses
	// function_call_output).
	RoleTool Role = "tool"
)

// PartKind is the type of a content [Part]. Plugins must treat unknown kinds
// as opaque: new kinds may be added in minor releases.
type PartKind string

const (
	// PartText is plain text; Text is set.
	PartText PartKind = "text"
	// PartImage is an image; URL or Data+MediaType is set. A data: URI stays
	// in URL undecoded, with MediaType set from the URI.
	PartImage PartKind = "image"
	// PartAudio is inline audio; Data holds the payload as received (base64
	// text for chat input_audio) and MediaType the format ("audio/wav").
	PartAudio PartKind = "audio"
	// PartFile is a file reference or inline file; URL, Data, or Raw is set.
	PartFile PartKind = "file"
	// PartToolCall is a tool invocation by the assistant; ToolCall is set.
	PartToolCall PartKind = "tool_call"
	// PartToolResult is the result of a tool call; ToolResult is set.
	PartToolResult PartKind = "tool_result"
	// PartReasoning is model reasoning text; Text is set.
	PartReasoning PartKind = "reasoning"
	// PartRefusal is a model refusal; Text is set.
	PartRefusal PartKind = "refusal"
	// PartOpaque is content GoModel does not model. Raw holds the original
	// encoding and the part round-trips unchanged.
	PartOpaque PartKind = "opaque"
)

// Part is one piece of message content.
type Part struct {
	Kind PartKind
	// Text is the content of text, reasoning, and refusal parts.
	Text string
	// MediaType is the MIME type of media parts, when known.
	MediaType string
	// Data is inline media as received; nil when URL-referenced.
	Data []byte
	// URL references remote or data-URI media.
	URL string
	// ToolCall is set for [PartToolCall].
	ToolCall *ToolCall
	// ToolResult is set for [PartToolResult].
	ToolResult *ToolResult
	// Raw is the original JSON encoding of parts GoModel keeps verbatim
	// (opaque parts, and media parts of the Responses dialect). Read-only.
	Raw json.RawMessage
}

// ToolCall is a tool invocation emitted by the model.
type ToolCall struct {
	// ID is the provider-visible call id (chat tool_calls[].id, Responses
	// call_id, Anthropic tool_use.id).
	ID string
	// Name is the tool name.
	Name string
	// Arguments is the argument JSON. When the wire format carried the
	// arguments as a string that parses as JSON, the parsed value is exposed;
	// otherwise a JSON string.
	Arguments json.RawMessage
	// Server is the MCP server name for calls routed through the MCP gateway.
	Server string
}

// ToolResult is the result returned for a tool call.
type ToolResult struct {
	// CallID matches ToolCall.ID.
	CallID string
	// Parts is the result content: text, image, or opaque parts.
	Parts []Part
	// IsError reports a failed tool execution (Anthropic is_error).
	IsError bool
}

// Message is one turn of the conversation.
type Message struct {
	// ID is stable within the exchange and survives edits. The host assigns
	// IDs; messages inserted by plugins get "new-N" IDs.
	ID   string
	Role Role
	// Parts is the content in order. Tool calls follow any text.
	Parts []Part
	// Name is the optional participant name (chat "name").
	Name string
	// ToolCallID links a [RoleTool] message to the call it answers.
	ToolCallID string
	// CacheBreakpoint reports an explicit prompt-cache marker on this
	// message (Anthropic cache_control).
	CacheBreakpoint bool
}

// TextMessage builds a message with a single text part.
func TextMessage(role Role, text string) Message {
	return Message{Role: role, Parts: []Part{{Kind: PartText, Text: text}}}
}

// Text returns the message's text parts concatenated in order. Tool result
// text is included for [RoleTool] messages.
func (m Message) Text() string {
	var b strings.Builder
	for _, part := range m.Parts {
		switch part.Kind {
		case PartText:
			b.WriteString(part.Text)
		case PartToolResult:
			if part.ToolResult == nil {
				continue
			}
			for _, inner := range part.ToolResult.Parts {
				if inner.Kind == PartText {
					b.WriteString(inner.Text)
				}
			}
		}
	}
	return b.String()
}