Documentation
¶
Index ¶
- Constants
- func AgentID(modelName string) string
- func ContainsDSMLSentinel(s string) bool
- func HasToolCalls(value any) bool
- func IsAgentCommonModel(modelName string) bool
- func IsDone(raw []byte) bool
- func ModelConfigSource(modelName string) string
- func NormalizeAssistantToolCallContent(messages []map[string]any) []map[string]any
- func NormalizeUsage(usage gjson.Result) json.RawMessage
- func NormalizeUsageBytes(raw []byte) json.RawMessage
- func ResidualSanitizerCheck(sanitized string) bool
- func ResolveErrorDetails(outerMessage, outerType, outerCode string, details json.RawMessage) (string, string, string)
- func SanitizeText(content string, opts SanitizeOptions) (string, []ToolCallDelta, []Diagnostic)
- func StripSSEPrefix(raw []byte) []byte
- func UnwrapBody(raw []byte) []byte
- type DSMLMode
- type Diagnostic
- type DiagnosticKind
- type ErrorInfo
- type Role
- type SSEEvent
- type SanitizeOptions
- type Sanitizer
- type TokenDetails
- type ToolCallDelta
- type Usage
Constants ¶
const ( AgentChat = "agent_chat" AgentCommon = "agent_common" SourceSystem = "system" )
Variables ¶
This section is empty.
Functions ¶
func AgentID ¶
AgentID returns the appropriate agent_id value for the given model name. Models that require agent_common get "agent_common"; all others get "agent_chat".
func ContainsDSMLSentinel ¶
ContainsDSMLSentinel reports whether s carries any DSML pipe marker, whether or not it sits inside a well-formed tag.
Adapters use it as a cheap post-condition: sanitized content that still matches means a leak slipped through and should be counted and logged. The check never rewrites anything, so it is safe to run on output that has already been sanitized.
func HasToolCalls ¶
HasToolCalls reports whether value represents a non-empty list of tool calls.
func IsAgentCommonModel ¶
IsAgentCommonModel reports whether the given model name requires the agent_common AgentId instead of agent_chat.
func IsDone ¶
IsDone checks if a Lingma SSE chunk indicates the end of the stream. It handles plain "[DONE]", "data: [DONE]", and the double-JSON envelope {"body":"[DONE]"}.
func ModelConfigSource ¶
ModelConfigSource returns the model_config.source value for the given model name. agent_chat models use "system" (enables reasoning); agent_common models use "".
func NormalizeAssistantToolCallContent ¶
NormalizeAssistantToolCallContent adapts OpenAI-compatible assistant tool-call history to the stricter provider behind Lingma. OpenAI permits content=null (or omitted content) when tool_calls is present, but that provider fails to recognize the tool_calls and then rejects the following tool result as orphaned. Setting content to "" preserves the message semantics while satisfying both schemas.
Only modifies messages satisfying all of: 1. role is "assistant" 2. tool_calls is non-empty 3. content is null or missing
Normal assistant, user, and tool messages with null content are preserved unchanged. The original slice and maps are not mutated in-place.
func NormalizeUsage ¶
func NormalizeUsage(usage gjson.Result) json.RawMessage
NormalizeUsage converts Lingma usage payloads into canonical OpenAI Chat Completions usage format.
func NormalizeUsageBytes ¶
func NormalizeUsageBytes(raw []byte) json.RawMessage
NormalizeUsageBytes parses raw JSON bytes and returns canonical OpenAI usage JSON.
func ResidualSanitizerCheck ¶
ResidualSanitizerCheck reports whether sanitized output still contains DSML markup. Adapters run it as a post-condition and count a hit as a defect: the sanitizer should have removed the markup, so a hit means a shape it does not yet know about reached the wire.
func ResolveErrorDetails ¶
func ResolveErrorDetails(outerMessage, outerType, outerCode string, details json.RawMessage) (string, string, string)
ResolveErrorDetails inspects the details field of a Lingma provider error envelope. Details may be:
- A JSON string encoding an inner error object: "{\"error\":{\"code\":...,\"message\":...,\"type\":...}}"
- A raw JSON object: {"error":{...}} or {"code":...,"message":...}
- A plain text string error message
- Null or missing
- Malformed JSON
It returns (resolvedMessage, resolvedType, resolvedCode). Inner error values take precedence over outer fields. If inner fields are missing, it falls back to the outer fields without losing errors.
func SanitizeText ¶
func SanitizeText(content string, opts SanitizeOptions) (string, []ToolCallDelta, []Diagnostic)
SanitizeText is the byte-in/byte-out entry point for non-streaming content, such as rewriting a message body before it is stored or forwarded. Streaming callers should use a Sanitizer so a split tag is never emitted early.
It returns the cleaned text, every call recovered from markup, and the diagnostics describing what was found.
func StripSSEPrefix ¶
StripSSEPrefix strips the "data:" or "event:" prefix and surrounding whitespace from an SSE line. If the line is an "event:" line or empty, returns nil.
func UnwrapBody ¶
UnwrapBody unwraps a double-JSON envelope if present: e.g. {"body": "{\"choices\":...}"} or {"body": {...}} Returns the unwrapped inner payload bytes, or the trimmed bytes if not wrapped.
Types ¶
type DSMLMode ¶
type DSMLMode uint8
DSMLMode selects how leaked DeepSeek tool markup is handled.
The zero value is DSMLRecover on purpose: Go zero values must not disable the protection that exists to keep sessions from stalling, so a caller using SanitizeOptions{} gets the useful behaviour.
type Diagnostic ¶
type Diagnostic struct {
Kind DiagnosticKind
Origin tagOrigin
Tool string
Text string
}
Diagnostic is one observation about leaked or recovered markup.
func (Diagnostic) String ¶
func (d Diagnostic) String() string
type DiagnosticKind ¶
type DiagnosticKind uint8
DiagnosticKind classifies a sanitizer observation.
const ( // DiagDroppedMarkup marks markup that was withheld without becoming a call. DiagDroppedMarkup DiagnosticKind = iota // DiagRecoveredCall marks a call reconstructed from leaked markup. DiagRecoveredCall // DiagUnknownTool marks a recoverable call whose tool was not declared. DiagUnknownTool // DiagDuplicateCall marks a recovered call the upstream already sent // natively, which is dropped to avoid executing it twice. DiagDuplicateCall // DiagResidualDSML marks DSML markup that survived sanitizing. DiagResidualDSML )
func (DiagnosticKind) String ¶
func (k DiagnosticKind) String() string
type ErrorInfo ¶
type ErrorInfo struct {
StatusCode int `json:"status_code"`
Message string `json:"message"`
Type string `json:"type"`
Code string `json:"code,omitempty"`
}
ErrorInfo contains structured information about an error returned by Lingma upstream.
func ParseError ¶
ParseError attempts to parse a Lingma SSE line or JSON response into an ErrorInfo. Returns (info, true) if an error was found, or (nil, false) if not an error.
type Role ¶
type Role uint8
Role is the author of the content being sanitized. Tool markup only ever belongs to assistant output; a user or tool message that contains a tool result is protocol, not pollution, and must survive.
type SSEEvent ¶
type SSEEvent struct {
// Type is "data", "finish", or "done".
Type string
// Content is the delta.content text (for text streaming).
Content string
// ReasoningContent is the delta.reasoning_content text (thinking/reasoning).
ReasoningContent string
// ToolCalls carries tool call deltas.
ToolCalls []ToolCallDelta
// FinishReason is set when the model finishes (e.g. "tool_calls", "stop").
FinishReason string
// Usage carries token usage (from finish/usage events).
Usage *Usage
// FirstTokenDuration is time-to-first-token in milliseconds from Lingma
// finish metadata.
FirstTokenDuration int
// HasError indicates the event contains an error.
HasError bool
// ErrorMsg is the error message when HasError is true.
ErrorMsg string
// ErrorType is the error type when HasError is true.
ErrorType string
// ErrorCode is the upstream error code when present.
ErrorCode string
// Raw is the raw inner JSON payload.
Raw []byte
}
SSEEvent is one normalized upstream stream event.
type SanitizeOptions ¶
type SanitizeOptions struct {
DSMLMode DSMLMode
Role Role
// KnownTools, when non-nil, restricts recovery to tools the request
// actually declared. A recovered name outside this set is stripped and
// reported instead of being turned into a call the client cannot serve.
KnownTools map[string]bool
// ThoughtTags routes thought spans into ReasoningContent instead of
// Content. Lingma wraps model reasoning this way.
ThoughtTags bool
// MaxHoldBytes bounds the buffer used to wait for a complete markup
// region. A model that opens markup and never closes it should not make
// the proxy hold an unbounded amount of text.
MaxHoldBytes int
}
SanitizeOptions configures a Sanitizer. The zero value is the recommended configuration for assistant output.
type Sanitizer ¶
type Sanitizer struct {
// contains filtered or unexported fields
}
Sanitizer is a streaming filter for model tool markup. Feed it content deltas in order and call Flush when the stream ends. It is not safe for concurrent use.
Holding text back is the whole point: a chunk boundary can land anywhere, including inside the three-byte fullwidth bar and between an opening tag and its closing tag. Emitting early would push markup downstream that the rest of the stream later proves was protocol.
func NewSanitizer ¶
func NewSanitizer(opts SanitizeOptions) *Sanitizer
NewSanitizer returns a Sanitizer for one message.
func (*Sanitizer) Diagnostics ¶
func (s *Sanitizer) Diagnostics() []Diagnostic
Diagnostics returns everything recorded so far and clears the record.
func (*Sanitizer) NoteNativeToolCalls ¶
func (s *Sanitizer) NoteNativeToolCalls(calls []ToolCallDelta)
NoteNativeToolCalls registers the structured tool calls the upstream already sent for this message, so a recovered duplicate can be dropped instead of being executed twice.
type TokenDetails ¶
type TokenDetails struct {
CachedTokens int `json:"cached_tokens,omitempty"`
ReasoningTokens int `json:"reasoning_tokens,omitempty"`
}
TokenDetails holds nested token counters.
type ToolCallDelta ¶
ToolCallDelta is a single streamed tool call.
type Usage ¶
type Usage struct {
PromptTokens int `json:"prompt_tokens"`
CompletionTokens int `json:"completion_tokens"`
TotalTokens int `json:"total_tokens"`
// Aliyun/Lingma aliases.
InputTokens int `json:"input_tokens"`
OutputTokens int `json:"output_tokens"`
// Cached and reasoning tokens.
CachedTokens int `json:"cached_tokens,omitempty"`
ReasoningTokens int `json:"reasoning_tokens,omitempty"`
// Nested details extracted from the Lingma response.
PromptTokensDetails *TokenDetails `json:"prompt_tokens_details,omitempty"`
CompletionTokensDetails *TokenDetails `json:"completion_tokens_details,omitempty"`
InputTokensDetails *TokenDetails `json:"input_tokens_details,omitempty"`
OutputTokensDetails *TokenDetails `json:"output_tokens_details,omitempty"`
}
Usage holds token accounting for one upstream response.
func (*Usage) Consolidate ¶
func (u *Usage) Consolidate()
Consolidate fills the OpenAI aliases and hoists nested counters.
func (*Usage) UnmarshalJSON ¶
UnmarshalJSON accepts the snake_case, camelCase, and provider-specific token counter names observed across Lingma envelope revisions.