Files
cc-connect/core/message.go
T
chenhg5andClaude b229ea5801 feat(cc-connect): add --stdin support and improve message sending
- Added --stdin support for sending multi-line/special character messages via heredoc

generated by llmgit

Co-Authored-By: Claude <noreply@anthropic.com>
2026-03-03 18:03:59 +08:00

113 lines
3.9 KiB
Go

package core
import (
"strings"
"time"
)
// MergeEnv returns base env with entries from extra overriding same-key entries.
// This prevents duplicate keys (e.g. two PATH entries) which cause the override
// to be silently ignored on Linux (getenv returns the first match).
func MergeEnv(base, extra []string) []string {
keys := make(map[string]bool, len(extra))
for _, e := range extra {
if k, _, ok := strings.Cut(e, "="); ok {
keys[k] = true
}
}
merged := make([]string, 0, len(base)+len(extra))
for _, e := range base {
if k, _, ok := strings.Cut(e, "="); ok && keys[k] {
continue
}
merged = append(merged, e)
}
return append(merged, extra...)
}
// AllowList checks whether a user ID is permitted based on a comma-separated
// allow_from string. Returns true if allowFrom is empty or "*" (allow all),
// or if the userID is in the list. Comparison is case-insensitive.
func AllowList(allowFrom, userID string) bool {
allowFrom = strings.TrimSpace(allowFrom)
if allowFrom == "" || allowFrom == "*" {
return true
}
for _, id := range strings.Split(allowFrom, ",") {
if strings.EqualFold(strings.TrimSpace(id), userID) {
return true
}
}
return false
}
// ImageAttachment represents an image sent by the user.
type ImageAttachment struct {
MimeType string // e.g. "image/png", "image/jpeg"
Data []byte // raw image bytes
FileName string // original filename (optional)
}
// AudioAttachment represents a voice/audio message sent by the user.
type AudioAttachment struct {
MimeType string // e.g. "audio/amr", "audio/ogg", "audio/mp4"
Data []byte // raw audio bytes
Format string // short format hint: "amr", "ogg", "m4a", "mp3", "wav", etc.
Duration int // duration in seconds (if known)
}
// Message represents a unified incoming message from any platform.
type Message struct {
SessionKey string // unique key for user context, e.g. "feishu:{chatID}:{userID}"
Platform string
UserID string
UserName string
Content string
Images []ImageAttachment // attached images (if any)
Audio *AudioAttachment // voice message (if any)
ReplyCtx any // platform-specific context needed for replying
}
// EventType distinguishes different kinds of agent output.
type EventType string
const (
EventText EventType = "text" // intermediate or final text
EventToolUse EventType = "tool_use" // tool invocation info
EventToolResult EventType = "tool_result" // tool execution result
EventResult EventType = "result" // final aggregated result
EventError EventType = "error" // error occurred
EventPermissionRequest EventType = "permission_request" // agent requests permission via stdio protocol
EventThinking EventType = "thinking" // thinking/processing status
)
// Event represents a single piece of agent output streamed back to the engine.
type Event struct {
Type EventType
Content string
ToolName string // populated for EventToolUse, EventPermissionRequest
ToolInput string // human-readable summary of tool input
ToolInputRaw map[string]any // raw tool input (for EventPermissionRequest, used in allow response)
ToolResult string // populated for EventToolResult
SessionID string // agent-managed session ID for conversation continuity
RequestID string // unique request ID for EventPermissionRequest
Done bool
Error error
}
// HistoryEntry is one turn in a conversation.
type HistoryEntry struct {
Role string `json:"role"` // "user" or "assistant"
Content string `json:"content"`
Timestamp time.Time `json:"timestamp"`
}
// AgentSessionInfo describes one session as reported by the agent backend.
type AgentSessionInfo struct {
ID string
Summary string
MessageCount int
ModifiedAt time.Time
GitBranch string
}