mirror of
https://github.com/cexll/myclaude.git
synced 2026-02-05 02:30:26 +08:00
Parser重复解析问题优化
This commit is contained in:
@@ -67,6 +67,34 @@ type codexHeader struct {
|
|||||||
} `json:"item,omitempty"`
|
} `json:"item,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// UnifiedEvent combines all backend event formats into a single structure
|
||||||
|
// to avoid multiple JSON unmarshal operations per event
|
||||||
|
type UnifiedEvent struct {
|
||||||
|
// Common fields
|
||||||
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
// Codex-specific fields
|
||||||
|
ThreadID string `json:"thread_id,omitempty"`
|
||||||
|
Item json.RawMessage `json:"item,omitempty"` // Lazy parse
|
||||||
|
|
||||||
|
// Claude-specific fields
|
||||||
|
Subtype string `json:"subtype,omitempty"`
|
||||||
|
SessionID string `json:"session_id,omitempty"`
|
||||||
|
Result string `json:"result,omitempty"`
|
||||||
|
|
||||||
|
// Gemini-specific fields
|
||||||
|
Role string `json:"role,omitempty"`
|
||||||
|
Content string `json:"content,omitempty"`
|
||||||
|
Delta bool `json:"delta,omitempty"`
|
||||||
|
Status string `json:"status,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ItemContent represents the parsed item.text field for Codex events
|
||||||
|
type ItemContent struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
Text interface{} `json:"text"`
|
||||||
|
}
|
||||||
|
|
||||||
func parseJSONStreamInternal(r io.Reader, warnFn func(string), infoFn func(string), onMessage func()) (message, threadID string) {
|
func parseJSONStreamInternal(r io.Reader, warnFn func(string), infoFn func(string), onMessage func()) (message, threadID string) {
|
||||||
reader := bufio.NewReaderSize(r, jsonLineReaderSize)
|
reader := bufio.NewReaderSize(r, jsonLineReaderSize)
|
||||||
|
|
||||||
@@ -112,71 +140,71 @@ func parseJSONStreamInternal(r io.Reader, warnFn func(string), infoFn func(strin
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
var codex codexHeader
|
// Single unmarshal for all backend types
|
||||||
if err := json.Unmarshal(line, &codex); err == nil {
|
var event UnifiedEvent
|
||||||
isCodex := codex.ThreadID != "" || (codex.Item != nil && codex.Item.Type != "")
|
|
||||||
if isCodex {
|
|
||||||
var details []string
|
|
||||||
if codex.ThreadID != "" {
|
|
||||||
details = append(details, fmt.Sprintf("thread_id=%s", codex.ThreadID))
|
|
||||||
}
|
|
||||||
if codex.Item != nil && codex.Item.Type != "" {
|
|
||||||
details = append(details, fmt.Sprintf("item_type=%s", codex.Item.Type))
|
|
||||||
}
|
|
||||||
if len(details) > 0 {
|
|
||||||
infoFn(fmt.Sprintf("Parsed event #%d type=%s (%s)", totalEvents, codex.Type, strings.Join(details, ", ")))
|
|
||||||
} else {
|
|
||||||
infoFn(fmt.Sprintf("Parsed event #%d type=%s", totalEvents, codex.Type))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch codex.Type {
|
|
||||||
case "thread.started":
|
|
||||||
threadID = codex.ThreadID
|
|
||||||
infoFn(fmt.Sprintf("thread.started event thread_id=%s", threadID))
|
|
||||||
case "item.completed":
|
|
||||||
itemType := ""
|
|
||||||
if codex.Item != nil {
|
|
||||||
itemType = codex.Item.Type
|
|
||||||
}
|
|
||||||
|
|
||||||
if itemType == "agent_message" {
|
|
||||||
var event JSONEvent
|
|
||||||
if err := json.Unmarshal(line, &event); err != nil {
|
if err := json.Unmarshal(line, &event); err != nil {
|
||||||
warnFn(fmt.Sprintf("Failed to parse Codex event: %s", truncateBytes(line, 100)))
|
warnFn(fmt.Sprintf("Failed to parse event: %s", truncateBytes(line, 100)))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
normalized := ""
|
// Detect backend type by field presence
|
||||||
if event.Item != nil {
|
isCodex := event.ThreadID != "" || len(event.Item) > 0
|
||||||
normalized = normalizeText(event.Item.Text)
|
isClaude := event.Subtype != "" || event.Result != ""
|
||||||
|
isGemini := event.Role != "" || event.Delta
|
||||||
|
|
||||||
|
// Handle Codex events
|
||||||
|
if isCodex {
|
||||||
|
var details []string
|
||||||
|
if event.ThreadID != "" {
|
||||||
|
details = append(details, fmt.Sprintf("thread_id=%s", event.ThreadID))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Parse item type if present
|
||||||
|
var itemType string
|
||||||
|
if len(event.Item) > 0 {
|
||||||
|
var itemHeader struct {
|
||||||
|
Type string `json:"type"`
|
||||||
|
}
|
||||||
|
if err := json.Unmarshal(event.Item, &itemHeader); err == nil {
|
||||||
|
itemType = itemHeader.Type
|
||||||
|
details = append(details, fmt.Sprintf("item_type=%s", itemType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(details) > 0 {
|
||||||
|
infoFn(fmt.Sprintf("Parsed event #%d type=%s (%s)", totalEvents, event.Type, strings.Join(details, ", ")))
|
||||||
|
} else {
|
||||||
|
infoFn(fmt.Sprintf("Parsed event #%d type=%s", totalEvents, event.Type))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch event.Type {
|
||||||
|
case "thread.started":
|
||||||
|
threadID = event.ThreadID
|
||||||
|
infoFn(fmt.Sprintf("thread.started event thread_id=%s", threadID))
|
||||||
|
|
||||||
|
case "item.completed":
|
||||||
|
if itemType == "agent_message" && len(event.Item) > 0 {
|
||||||
|
// Lazy parse: only parse item content when needed
|
||||||
|
var item ItemContent
|
||||||
|
if err := json.Unmarshal(event.Item, &item); err == nil {
|
||||||
|
normalized := normalizeText(item.Text)
|
||||||
infoFn(fmt.Sprintf("item.completed event item_type=%s message_len=%d", itemType, len(normalized)))
|
infoFn(fmt.Sprintf("item.completed event item_type=%s message_len=%d", itemType, len(normalized)))
|
||||||
if normalized != "" {
|
if normalized != "" {
|
||||||
codexMessage = normalized
|
codexMessage = normalized
|
||||||
notifyMessage()
|
notifyMessage()
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
warnFn(fmt.Sprintf("Failed to parse item content: %s", err.Error()))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
infoFn(fmt.Sprintf("item.completed event item_type=%s", itemType))
|
infoFn(fmt.Sprintf("item.completed event item_type=%s", itemType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var raw map[string]json.RawMessage
|
|
||||||
if err := json.Unmarshal(line, &raw); err != nil {
|
|
||||||
warnFn(fmt.Sprintf("Failed to parse line: %s", truncateBytes(line, 100)))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case hasKey(raw, "subtype") || hasKey(raw, "result"):
|
|
||||||
var event ClaudeEvent
|
|
||||||
if err := json.Unmarshal(line, &event); err != nil {
|
|
||||||
warnFn(fmt.Sprintf("Failed to parse Claude event: %s", truncateBytes(line, 100)))
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Handle Claude events
|
||||||
|
if isClaude {
|
||||||
if event.SessionID != "" && threadID == "" {
|
if event.SessionID != "" && threadID == "" {
|
||||||
threadID = event.SessionID
|
threadID = event.SessionID
|
||||||
}
|
}
|
||||||
@@ -187,14 +215,11 @@ func parseJSONStreamInternal(r io.Reader, warnFn func(string), infoFn func(strin
|
|||||||
claudeMessage = event.Result
|
claudeMessage = event.Result
|
||||||
notifyMessage()
|
notifyMessage()
|
||||||
}
|
}
|
||||||
|
|
||||||
case hasKey(raw, "role") || hasKey(raw, "delta"):
|
|
||||||
var event GeminiEvent
|
|
||||||
if err := json.Unmarshal(line, &event); err != nil {
|
|
||||||
warnFn(fmt.Sprintf("Failed to parse Gemini event: %s", truncateBytes(line, 100)))
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Handle Gemini events
|
||||||
|
if isGemini {
|
||||||
if event.SessionID != "" && threadID == "" {
|
if event.SessionID != "" && threadID == "" {
|
||||||
threadID = event.SessionID
|
threadID = event.SessionID
|
||||||
}
|
}
|
||||||
@@ -205,10 +230,11 @@ func parseJSONStreamInternal(r io.Reader, warnFn func(string), infoFn func(strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
infoFn(fmt.Sprintf("Parsed Gemini event #%d type=%s role=%s delta=%t status=%s content_len=%d", totalEvents, event.Type, event.Role, event.Delta, event.Status, len(event.Content)))
|
infoFn(fmt.Sprintf("Parsed Gemini event #%d type=%s role=%s delta=%t status=%s content_len=%d", totalEvents, event.Type, event.Role, event.Delta, event.Status, len(event.Content)))
|
||||||
|
continue
|
||||||
default:
|
|
||||||
warnFn(fmt.Sprintf("Unknown event format: %s", truncateBytes(line, 100)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unknown event format
|
||||||
|
warnFn(fmt.Sprintf("Unknown event format: %s", truncateBytes(line, 100)))
|
||||||
}
|
}
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
|
|||||||
Reference in New Issue
Block a user