88 lines
2.4 KiB
Go
88 lines
2.4 KiB
Go
package format
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
// Formatting constants for the 9P chat log protocol.
|
|
// Used by fs.NewEventHandler and fs.replayMessagesToLog.
|
|
|
|
const (
|
|
// EndTag marks the end of a message block.
|
|
EndTag = "[[[end]]]"
|
|
|
|
// RoleTag formats a role delimiter, e.g. "[[[user]]]".
|
|
RoleTag = "[[[%s]]]"
|
|
|
|
// ToolFence is the opening fence for tool output blocks.
|
|
ToolFence = "```\n"
|
|
|
|
// AssistantHeaderPrefix is prepended to assistant headers when a response ID is present.
|
|
AssistantHeaderPrefix = "[[[assistant:"
|
|
|
|
// AssistantTag is the bare assistant header (no response ID).
|
|
AssistantTag = "[[[assistant]]]"
|
|
|
|
// UserTag is the user role delimiter.
|
|
UserTag = "[[[user]]]"
|
|
|
|
// RetryTag is the retry role delimiter.
|
|
RetryTag = "[[[retry]]]"
|
|
|
|
// ToolDelimPrefix is the prefix for tool delimiters, e.g. "[[[tool:shell]]]".
|
|
ToolDelimPrefix = "[[[tool:"
|
|
|
|
// ToolTag is the bare tool role delimiter (no name).
|
|
ToolTag = "[[[tool]]]"
|
|
|
|
// CallDelimPrefix is the prefix for call delimiters, e.g. "[[[call:file_read]]]".
|
|
CallDelimPrefix = "[[[call:"
|
|
)
|
|
|
|
// RoleDelim returns a formatted role delimiter.
|
|
func RoleDelim(role string) string {
|
|
return fmt.Sprintf(RoleTag, role)
|
|
}
|
|
|
|
// ToolDelim returns a formatted tool delimiter.
|
|
func ToolDelim(name string) string {
|
|
return fmt.Sprintf(ToolDelimPrefix+"%s]]]\n", name)
|
|
}
|
|
|
|
// CallDelim returns a formatted call delimiter.
|
|
func CallDelim(name string) string {
|
|
return fmt.Sprintf(CallDelimPrefix+"%s]]]\n", name)
|
|
}
|
|
|
|
// BlockHeader is a single-line [[[...]]] marker that opens a log block.
|
|
type BlockHeader struct {
|
|
Role string // e.g. "user", "assistant", "tool", "retry", or "tool:shell"
|
|
Name string // for tool/call: the sub-name (e.g. "shell"), empty for bare roles
|
|
}
|
|
|
|
// ParseBlockHeader extracts a BlockHeader from a line like "[[[tool:shell]]]"
|
|
// or "[[[assistant]]]". Returns nil if the line is not a valid block header.
|
|
func ParseBlockHeader(line string) *BlockHeader {
|
|
const prefix, suffix = "[[[", "]]]"
|
|
if !strings.HasPrefix(line, prefix) || !strings.HasSuffix(line, suffix) {
|
|
return nil
|
|
}
|
|
inner := strings.TrimPrefix(line, prefix)
|
|
inner = strings.TrimSuffix(inner, suffix)
|
|
if inner == "" {
|
|
return nil
|
|
}
|
|
bh := &BlockHeader{Role: inner}
|
|
if idx := strings.Index(inner, ":"); idx >= 0 {
|
|
bh.Role = inner[:idx]
|
|
bh.Name = inner[idx+1:]
|
|
}
|
|
return bh
|
|
}
|
|
|
|
// IsEndMarker reports whether the line is exactly the [[[end]]] closing marker.
|
|
func IsEndMarker(line string) bool {
|
|
return line == EndTag
|
|
}
|