chore: prepare GoodBuddy 0.8.5

This commit is contained in:
lofyer
2026-08-07 10:45:01 +08:00
parent e20cb447af
commit 17e66a3369
54 changed files with 1306 additions and 1640 deletions
+98
View File
@@ -82,6 +82,7 @@ type ModelToolCall = {
type ModelToolResponse = {
text: string
reasoning: string
toolCalls: ModelToolCall[]
assistantMessage?: Record<string, unknown>
responsesOutput?: Array<Record<string, unknown>>
@@ -162,6 +163,25 @@ function getAnthropicTextDelta(value: unknown): string | undefined {
return undefined
}
function getAnthropicReasoningDelta(value: unknown): string | undefined {
if (
!value ||
typeof value !== 'object' ||
!('type' in value) ||
value.type !== 'content_block_delta' ||
!('delta' in value) ||
!value.delta ||
typeof value.delta !== 'object' ||
!('type' in value.delta) ||
value.delta.type !== 'thinking_delta' ||
!('thinking' in value.delta) ||
typeof value.delta.thinking !== 'string'
) {
return undefined
}
return value.delta.thinking
}
function getOpenAITextDelta(value: unknown): string | undefined {
if (
!value ||
@@ -186,6 +206,22 @@ function getOpenAITextDelta(value: unknown): string | undefined {
return first.delta.content
}
function getOpenAIReasoningDelta(value: unknown): string | undefined {
if (
!value ||
typeof value !== 'object' ||
!('choices' in value) ||
!Array.isArray(value.choices)
) {
return undefined
}
const first = getRecord(value.choices[0])
const delta = getRecord(first?.delta)
const reasoning =
delta?.reasoning_content ?? delta?.reasoning ?? delta?.thinking
return typeof reasoning === 'string' ? reasoning : undefined
}
function getOpenAIResponsesTextDelta(
value: unknown
): string | undefined {
@@ -202,6 +238,19 @@ function getOpenAIResponsesTextDelta(
return value.delta
}
function getOpenAIResponsesReasoningDelta(
value: unknown
): string | undefined {
const event = getRecord(value)
if (
event?.type !== 'response.reasoning_summary_text.delta' &&
event?.type !== 'response.reasoning_text.delta'
) {
return undefined
}
return typeof event.delta === 'string' ? event.delta : undefined
}
function getRecord(
value: unknown
): Record<string, unknown> | undefined {
@@ -647,6 +696,7 @@ function parseModelToolResponse(
throw new Error('Anthropic 模型接口未返回 content')
}
const text: string[] = []
const reasoning: string[] = []
const toolCalls: ModelToolCall[] = []
for (const block of payload.content) {
const record = getRecord(block)
@@ -655,6 +705,11 @@ function parseModelToolResponse(
}
if (record.type === 'text' && typeof record.text === 'string') {
text.push(record.text)
} else if (
record.type === 'thinking' &&
typeof record.thinking === 'string'
) {
reasoning.push(record.thinking)
} else if (record.type === 'tool_use') {
const identity = parseToolCallIdentity(record.id, record.name)
toolCalls.push({
@@ -665,6 +720,7 @@ function parseModelToolResponse(
}
return {
text: text.join(''),
reasoning: reasoning.join(''),
toolCalls,
assistantMessage: {
role: 'assistant',
@@ -696,6 +752,7 @@ function parseModelToolResponse(
throw new Error('OpenAI Responses 接口返回格式无效')
}
const text: string[] = []
const reasoning: string[] = []
const toolCalls: ModelToolCall[] = []
for (const item of payload.output) {
const output = getRecord(item)
@@ -712,6 +769,20 @@ function parseModelToolResponse(
text.push(content.text)
}
}
} else if (output.type === 'reasoning') {
for (const part of [
...(Array.isArray(output.summary) ? output.summary : []),
...(Array.isArray(output.content) ? output.content : [])
]) {
const content = getRecord(part)
if (
(content?.type === 'summary_text' ||
content?.type === 'reasoning_text') &&
typeof content.text === 'string'
) {
reasoning.push(content.text)
}
}
} else if (output.type === 'function_call') {
const identity = parseToolCallIdentity(
output.call_id,
@@ -725,6 +796,7 @@ function parseModelToolResponse(
}
return {
text: text.join(''),
reasoning: reasoning.join(''),
toolCalls,
responsesOutput: payload.output.flatMap((item) => {
const output = getRecord(item)
@@ -743,6 +815,10 @@ function parseModelToolResponse(
throw new Error('OpenAI 模型接口未返回 assistant message')
}
const text = typeof message.content === 'string' ? message.content : ''
const reasoningValue =
message.reasoning_content ?? message.reasoning ?? message.thinking
const reasoning =
typeof reasoningValue === 'string' ? reasoningValue : ''
const toolCalls: ModelToolCall[] = []
if (message.tool_calls !== undefined) {
if (!Array.isArray(message.tool_calls)) {
@@ -766,6 +842,7 @@ function parseModelToolResponse(
}
return {
text,
reasoning,
toolCalls,
assistantMessage: {
role: 'assistant',
@@ -783,6 +860,7 @@ function parseStreamBlock(
protocol: ModelProtocol
): {
delta?: string
reasoningDelta?: string
stopped: boolean
usage?: ModelUsageUpdate
} {
@@ -840,6 +918,12 @@ function parseStreamBlock(
: protocol === 'openai-responses'
? getOpenAIResponsesTextDelta(event)
: getOpenAITextDelta(event),
reasoningDelta:
protocol === 'anthropic-messages'
? getAnthropicReasoningDelta(event)
: protocol === 'openai-responses'
? getOpenAIResponsesReasoningDelta(event)
: getOpenAIReasoningDelta(event),
usage: getUsageUpdate(
event,
protocol === 'anthropic-messages' ? 'anthropic' : 'openai'
@@ -1380,6 +1464,13 @@ export class ModelAgentRuntime implements AgentRuntime {
if (usageEvent) {
yield usageEvent
}
if (response.reasoning) {
yield {
requestId: request.requestId,
type: 'reasoning',
delta: response.reasoning
}
}
if (response.text) {
answer += response.text
if (Buffer.byteLength(answer) > 1024 * 1024) {
@@ -1748,6 +1839,13 @@ export class ModelAgentRuntime implements AgentRuntime {
if (parsed.usage) {
applyUsageUpdate(usage, parsed.usage)
}
if (parsed.reasoningDelta) {
yield {
requestId: request.requestId,
type: 'reasoning',
delta: parsed.reasoningDelta
}
}
const { delta } = parsed
if (delta) {
answer += delta