Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion internal/agents/conductor.go
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,19 @@ func (a *ConductorAgent) Run(ctx context.Context, input string, mem *memory.Conv

if choice.Content != "" {
if a.Publisher != nil {
a.Publisher.Publish("ai_response", choice.Content, a.Name())
metadata := map[string]interface{}{}
if resp.Usage != nil {
metadata["usage"] = map[string]interface{}{
"prompt_tokens": resp.Usage.PromptTokens,
"completion_tokens": resp.Usage.CompletionTokens,
"total_tokens": resp.Usage.TotalTokens,
}
}
if len(metadata) > 0 {
a.Publisher.PublishWithMetadata("ai_response", choice.Content, a.Name(), metadata)
} else {
a.Publisher.Publish("ai_response", choice.Content, a.Name())
}
}
}

Expand Down
14 changes: 13 additions & 1 deletion internal/agents/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,19 @@ func RunAgentLoop(ctx context.Context, cfg ExecutorConfig) (string, error) {

choice := resp.Choices[0]
if choice.Content != "" && cfg.Publisher != nil {
cfg.Publisher.Publish("ai_response", choice.Content, cfg.AgentName)
metadata := map[string]interface{}{}
if resp.Usage != nil {
metadata["usage"] = map[string]interface{}{
"prompt_tokens": resp.Usage.PromptTokens,
"completion_tokens": resp.Usage.CompletionTokens,
"total_tokens": resp.Usage.TotalTokens,
}
}
if len(metadata) > 0 {
cfg.Publisher.PublishWithMetadata("ai_response", choice.Content, cfg.AgentName, metadata)
} else {
cfg.Publisher.Publish("ai_response", choice.Content, cfg.AgentName)
}
}

// Build assistant message
Expand Down
14 changes: 13 additions & 1 deletion internal/agents/meta.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,19 @@ func (a *MetaAgent) Run(ctx context.Context, input string) (string, error) {
}

if a.Publisher != nil {
a.Publisher.Publish("ai_response", content, a.Name())
metadata := map[string]interface{}{}
if resp.Usage != nil {
metadata["usage"] = map[string]interface{}{
"prompt_tokens": resp.Usage.PromptTokens,
"completion_tokens": resp.Usage.CompletionTokens,
"total_tokens": resp.Usage.TotalTokens,
}
}
if len(metadata) > 0 {
a.Publisher.PublishWithMetadata("ai_response", content, a.Name(), metadata)
} else {
a.Publisher.Publish("ai_response", content, a.Name())
}
}

return content, nil
Expand Down
10 changes: 9 additions & 1 deletion internal/llm/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,17 @@ type FunctionCall struct {
Arguments string `json:"arguments"`
}

// TokenUsage contains token usage information returned by the LLM API.
type TokenUsage struct {
PromptTokens int64 `json:"prompt_tokens"`
CompletionTokens int64 `json:"completion_tokens"`
TotalTokens int64 `json:"total_tokens"`
}

// Response represents the LLM's response to a GenerateContent call.
type Response struct {
Choices []Choice `json:"choices"`
Choices []Choice `json:"choices"`
Usage *TokenUsage `json:"usage,omitempty"`
}

// Choice represents a single choice in the LLM response.
Expand Down
21 changes: 21 additions & 0 deletions internal/llm/engine_openai.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,12 +129,23 @@ func (e *OpenAIEngine) generateStreaming(ctx context.Context, params openai.Chat
return nil, fmt.Errorf("openai streaming: %w", err)
}

// Extract real token usage from streaming accumulator
var usage *TokenUsage
if acc := stream.Current(); acc.Usage.PromptTokens > 0 || acc.Usage.CompletionTokens > 0 {
usage = &TokenUsage{
PromptTokens: acc.Usage.PromptTokens,
CompletionTokens: acc.Usage.CompletionTokens,
TotalTokens: acc.Usage.TotalTokens,
}
}

return &Response{
Choices: []Choice{{
Content: content,
Reasoning: reasoning,
ToolCalls: toolCalls,
}},
Usage: usage,
}, nil
}

Expand Down Expand Up @@ -260,5 +271,15 @@ func (e *OpenAIEngine) toResponse(completion *openai.ChatCompletion) *Response {

resp.Choices = append(resp.Choices, c)
}

// Extract real token usage from API response
if completion.Usage.PromptTokens > 0 || completion.Usage.CompletionTokens > 0 {
resp.Usage = &TokenUsage{
PromptTokens: completion.Usage.PromptTokens,
CompletionTokens: completion.Usage.CompletionTokens,
TotalTokens: completion.Usage.TotalTokens,
}
}

return resp
}
5 changes: 0 additions & 5 deletions internal/tui/i18n.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ type translations struct {
ConfirmDialogYes string
ConfirmDialogNo string
// Command mode (vim-like modal editing)
CommandModePrompt string
CommandModeTips string
CommandModeIdleTips string
EditModeTips string
Expand Down Expand Up @@ -97,7 +96,6 @@ var langMap = map[Language]translations{
ConfirmCancelMessage: "确定要取消当前任务吗?",
ConfirmDialogYes: "确认 (Enter)",
ConfirmDialogNo: "取消 (Esc)",
CommandModePrompt: "命令",
CommandModeTips: "gg/G:首/尾 j/k:上下 f/b:翻页 ctrl+d/u:半页 i:编辑 ctrl+e:编辑模式 ZZ:退出",
CommandModeIdleTips: "gg/G:首/尾 j/k:上下 f/b:翻页 ctrl+d/u:半页 ::命令 /:搜索 ?:帮助 i:编辑 ZZ:退出",
EditModeTips: "ctrl+s:提交 ctrl+e:命令模式 ctrl+h:历史 ctrl+l:语言 ctrl+c:退出",
Expand Down Expand Up @@ -161,7 +159,6 @@ var langMap = map[Language]translations{
ConfirmCancelMessage: "Are you sure you want to cancel the current task?",
ConfirmDialogYes: "Confirm (Enter)",
ConfirmDialogNo: "Cancel (Esc)",
CommandModePrompt: "COMMAND",
CommandModeTips: "gg/G:top/btm j/k:scroll f/b:pgdn/up ctrl+d/u:half i:edit ctrl+e:edit ZZ:quit",
CommandModeIdleTips: "gg/G:top/btm j/k:scroll f/b:pgdn/up ctrl+d/u:half ::cmd /:search ?:help i:edit ZZ:quit",
EditModeTips: "ctrl+s:submit ctrl+e:cmd ctrl+h:history ctrl+l:lang ctrl+c:quit",
Expand Down Expand Up @@ -288,8 +285,6 @@ func (lm *LanguageManager) GetText(key string) string {
return translations.ConfirmDialogYes
case "ConfirmDialogNo":
return translations.ConfirmDialogNo
case "CommandModePrompt":
return translations.CommandModePrompt
case "CommandModeTips":
return translations.CommandModeTips
case "CommandModeIdleTips":
Expand Down
Loading