fix: correct token calculation in prompt tool use plugin (#11867)

* fix: correct token calculation in prompt tool use plugin

- Fix duplicate token accumulation in recursive stream handling
- Accumulate usage for finish-step without tool calls
- Filter out recursive stream's start/finish events (only one per conversation)
- Make accumulateUsage method public for reuse

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

* refactor: simplify pipeRecursiveStream method in StreamEventManager

- Removed unnecessary context parameter from pipeRecursiveStream method
- Streamlined the invocation of pipeRecursiveStream in recursive call handling

This change enhances code clarity and reduces complexity in stream management.

---------

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
MyPrototypeWhat 2025-12-12 18:23:49 +08:00 committed by GitHub
parent 97f6275104
commit 96aba33077
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 12 additions and 17 deletions

View File

@ -62,7 +62,7 @@ export class StreamEventManager {
const recursiveResult = await context.recursiveCall(recursiveParams) const recursiveResult = await context.recursiveCall(recursiveParams)
if (recursiveResult && recursiveResult.fullStream) { if (recursiveResult && recursiveResult.fullStream) {
await this.pipeRecursiveStream(controller, recursiveResult.fullStream, context) await this.pipeRecursiveStream(controller, recursiveResult.fullStream)
} else { } else {
console.warn('[MCP Prompt] No fullstream found in recursive result:', recursiveResult) console.warn('[MCP Prompt] No fullstream found in recursive result:', recursiveResult)
} }
@ -74,11 +74,7 @@ export class StreamEventManager {
/** /**
* *
*/ */
private async pipeRecursiveStream( private async pipeRecursiveStream(controller: StreamController, recursiveStream: ReadableStream): Promise<void> {
controller: StreamController,
recursiveStream: ReadableStream,
context?: AiRequestContext
): Promise<void> {
const reader = recursiveStream.getReader() const reader = recursiveStream.getReader()
try { try {
while (true) { while (true) {
@ -86,18 +82,14 @@ export class StreamEventManager {
if (done) { if (done) {
break break
} }
if (value.type === 'finish') { if (value.type === 'start') {
// 迭代的流不发finish但需要累加其 usage continue
if (value.usage && context?.accumulatedUsage) {
this.accumulateUsage(context.accumulatedUsage, value.usage)
} }
if (value.type === 'finish') {
break break
} }
// 对于 finish-step 类型,累加其 usage
if (value.type === 'finish-step' && value.usage && context?.accumulatedUsage) {
this.accumulateUsage(context.accumulatedUsage, value.usage)
}
// 将递归流的数据传递到当前流
controller.enqueue(value) controller.enqueue(value)
} }
} finally { } finally {
@ -159,7 +151,7 @@ export class StreamEventManager {
/** /**
* usage * usage
*/ */
private accumulateUsage(target: any, source: any): void { accumulateUsage(target: any, source: any): void {
if (!target || !source) return if (!target || !source) return
// 累加各种 token 类型 // 累加各种 token 类型

View File

@ -411,7 +411,10 @@ export const createPromptToolUsePlugin = (config: PromptToolUseConfig = {}) => {
} }
} }
// 如果没有执行工具调用直接传递原始finish-step事件 // 如果没有执行工具调用,累加 usage 后透传 finish-step 事件
if (chunk.usage && context.accumulatedUsage) {
streamEventManager.accumulateUsage(context.accumulatedUsage, chunk.usage)
}
controller.enqueue(chunk) controller.enqueue(chunk)
// 清理状态 // 清理状态