summaryrefslogtreecommitdiffhomepage
path: root/internal/message/content.go
diff options
context:
space:
mode:
authorKujtim Hoxha <[email protected]>2025-04-03 15:20:15 +0200
committerKujtim Hoxha <[email protected]>2025-04-03 17:23:41 +0200
commitcfdd687216799cb5b47f099f1e7cd5dd16b3bdd0 (patch)
treea822bfde1463a7080c0ea06dd17796d7a1617d3d /internal/message/content.go
parentafd9ad0560d76c2a6d161dad52553b10ff428905 (diff)
downloadopencode-cfdd687216799cb5b47f099f1e7cd5dd16b3bdd0.tar.gz
opencode-cfdd687216799cb5b47f099f1e7cd5dd16b3bdd0.zip
add initial lsp support
Diffstat (limited to 'internal/message/content.go')
-rw-r--r--internal/message/content.go244
1 files changed, 244 insertions, 0 deletions
diff --git a/internal/message/content.go b/internal/message/content.go
new file mode 100644
index 000000000..2604cd68a
--- /dev/null
+++ b/internal/message/content.go
@@ -0,0 +1,244 @@
+package message
+
+import (
+ "encoding/base64"
+)
+
+type MessageRole string
+
+const (
+ Assistant MessageRole = "assistant"
+ User MessageRole = "user"
+ System MessageRole = "system"
+ Tool MessageRole = "tool"
+)
+
+type ContentPart interface {
+ isPart()
+}
+
+type ReasoningContent struct {
+ Thinking string `json:"thinking"`
+}
+
+func (tc ReasoningContent) String() string {
+ return tc.Thinking
+}
+func (ReasoningContent) isPart() {}
+
+type TextContent struct {
+ Text string `json:"text"`
+}
+
+func (tc TextContent) String() string {
+ return tc.Text
+}
+
+func (TextContent) isPart() {}
+
+type ImageURLContent struct {
+ URL string `json:"url"`
+ Detail string `json:"detail,omitempty"`
+}
+
+func (iuc ImageURLContent) String() string {
+ return iuc.URL
+}
+
+func (ImageURLContent) isPart() {}
+
+type BinaryContent struct {
+ MIMEType string
+ Data []byte
+}
+
+func (bc BinaryContent) String() string {
+ base64Encoded := base64.StdEncoding.EncodeToString(bc.Data)
+ return "data:" + bc.MIMEType + ";base64," + base64Encoded
+}
+
+func (BinaryContent) isPart() {}
+
+type ToolCall struct {
+ ID string `json:"id"`
+ Name string `json:"name"`
+ Input string `json:"input"`
+ Type string `json:"type"`
+ Finished bool `json:"finished"`
+}
+
+func (ToolCall) isPart() {}
+
+type ToolResult struct {
+ ToolCallID string `json:"tool_call_id"`
+ Name string `json:"name"`
+ Content string `json:"content"`
+ IsError bool `json:"is_error"`
+}
+
+func (ToolResult) isPart() {}
+
+type Finish struct {
+ Reason string `json:"reason"`
+}
+
+func (Finish) isPart() {}
+
+type Message struct {
+ ID string
+ Role MessageRole
+ SessionID string
+ Parts []ContentPart
+
+ CreatedAt int64
+ UpdatedAt int64
+}
+
+func (m *Message) Content() TextContent {
+ for _, part := range m.Parts {
+ if c, ok := part.(TextContent); ok {
+ return c
+ }
+ }
+ return TextContent{}
+}
+
+func (m *Message) ReasoningContent() ReasoningContent {
+ for _, part := range m.Parts {
+ if c, ok := part.(ReasoningContent); ok {
+ return c
+ }
+ }
+ return ReasoningContent{}
+}
+
+func (m *Message) ImageURLContent() []ImageURLContent {
+ imageURLContents := make([]ImageURLContent, 0)
+ for _, part := range m.Parts {
+ if c, ok := part.(ImageURLContent); ok {
+ imageURLContents = append(imageURLContents, c)
+ }
+ }
+ return imageURLContents
+}
+
+func (m *Message) BinaryContent() []BinaryContent {
+ binaryContents := make([]BinaryContent, 0)
+ for _, part := range m.Parts {
+ if c, ok := part.(BinaryContent); ok {
+ binaryContents = append(binaryContents, c)
+ }
+ }
+ return binaryContents
+}
+
+func (m *Message) ToolCalls() []ToolCall {
+ toolCalls := make([]ToolCall, 0)
+ for _, part := range m.Parts {
+ if c, ok := part.(ToolCall); ok {
+ toolCalls = append(toolCalls, c)
+ }
+ }
+ return toolCalls
+}
+
+func (m *Message) ToolResults() []ToolResult {
+ toolResults := make([]ToolResult, 0)
+ for _, part := range m.Parts {
+ if c, ok := part.(ToolResult); ok {
+ toolResults = append(toolResults, c)
+ }
+ }
+ return toolResults
+}
+
+func (m *Message) IsFinished() bool {
+ for _, part := range m.Parts {
+ if _, ok := part.(Finish); ok {
+ return true
+ }
+ }
+ return false
+}
+
+func (m *Message) FinishReason() string {
+ for _, part := range m.Parts {
+ if c, ok := part.(Finish); ok {
+ return c.Reason
+ }
+ }
+ return ""
+}
+
+func (m *Message) IsThinking() bool {
+ if m.ReasoningContent().Thinking != "" && m.Content().Text == "" && !m.IsFinished() {
+ return true
+ }
+ return false
+}
+
+func (m *Message) AppendContent(delta string) {
+ found := false
+ for i, part := range m.Parts {
+ if c, ok := part.(TextContent); ok {
+ m.Parts[i] = TextContent{Text: c.Text + delta}
+ found = true
+ }
+ }
+ if !found {
+ m.Parts = append(m.Parts, TextContent{Text: delta})
+ }
+}
+
+func (m *Message) AppendReasoningContent(delta string) {
+ found := false
+ for i, part := range m.Parts {
+ if c, ok := part.(ReasoningContent); ok {
+ m.Parts[i] = ReasoningContent{Thinking: c.Thinking + delta}
+ found = true
+ }
+ }
+ if !found {
+ m.Parts = append(m.Parts, ReasoningContent{Thinking: delta})
+ }
+}
+
+func (m *Message) AddToolCall(tc ToolCall) {
+ for i, part := range m.Parts {
+ if c, ok := part.(ToolCall); ok {
+ if c.ID == tc.ID {
+ m.Parts[i] = tc
+ return
+ }
+ }
+ }
+ m.Parts = append(m.Parts, tc)
+}
+
+func (m *Message) SetToolCalls(tc []ToolCall) {
+ for _, toolCall := range tc {
+ m.Parts = append(m.Parts, toolCall)
+ }
+}
+
+func (m *Message) AddToolResult(tr ToolResult) {
+ m.Parts = append(m.Parts, tr)
+}
+
+func (m *Message) SetToolResults(tr []ToolResult) {
+ for _, toolResult := range tr {
+ m.Parts = append(m.Parts, toolResult)
+ }
+}
+
+func (m *Message) AddFinish(reason string) {
+ m.Parts = append(m.Parts, Finish{Reason: reason})
+}
+
+func (m *Message) AddImageURL(url, detail string) {
+ m.Parts = append(m.Parts, ImageURLContent{URL: url, Detail: detail})
+}
+
+func (m *Message) AddBinary(mimeType string, data []byte) {
+ m.Parts = append(m.Parts, BinaryContent{MIMEType: mimeType, Data: data})
+}