Skip to content

Commit 8a0bbfa

Browse files
committed
refactor: factor reasoning history building into helper
1 parent 5cabc4f commit 8a0bbfa

File tree

1 file changed

+86
-80
lines changed

1 file changed

+86
-80
lines changed

src/core/task/Task.ts

Lines changed: 86 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -2922,88 +2922,9 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
29222922
}
29232923
}
29242924

2925-
// Properly type cleaned conversation history to include either standard Anthropic messages
2926-
// or provider-specific reasoning items (for encrypted continuity).
2927-
type ReasoningItemForRequest = {
2928-
type: "reasoning"
2929-
encrypted_content: string
2930-
id?: string
2931-
summary?: any[]
2932-
}
2933-
type CleanConversationMessage = Anthropic.Messages.MessageParam | ReasoningItemForRequest
2934-
29352925
const messagesSinceLastSummary = getMessagesSinceLastSummary(this.apiConversationHistory)
29362926
const messagesWithoutImages = maybeRemoveImageBlocks(messagesSinceLastSummary, this.api)
2937-
const cleanConversationHistory: CleanConversationMessage[] = []
2938-
2939-
for (const msg of messagesWithoutImages as ApiMessage[]) {
2940-
// Legacy path: standalone reasoning items stored as separate messages
2941-
if (msg.type === "reasoning" && msg.encrypted_content) {
2942-
cleanConversationHistory.push({
2943-
type: "reasoning",
2944-
summary: msg.summary,
2945-
encrypted_content: msg.encrypted_content!,
2946-
...(msg.id ? { id: msg.id } : {}),
2947-
})
2948-
continue
2949-
}
2950-
2951-
// Preferred path: assistant message with embedded reasoning as first content block
2952-
if (msg.role === "assistant") {
2953-
const rawContent = msg.content
2954-
2955-
const contentArray: Anthropic.Messages.ContentBlockParam[] = Array.isArray(rawContent)
2956-
? (rawContent as Anthropic.Messages.ContentBlockParam[])
2957-
: rawContent !== undefined
2958-
? ([
2959-
{ type: "text", text: rawContent } satisfies Anthropic.Messages.TextBlockParam,
2960-
] as Anthropic.Messages.ContentBlockParam[])
2961-
: []
2962-
2963-
const [first, ...rest] = contentArray
2964-
2965-
const hasEmbeddedReasoning =
2966-
first && (first as any).type === "reasoning" && typeof (first as any).encrypted_content === "string"
2967-
2968-
if (hasEmbeddedReasoning) {
2969-
const reasoningBlock = first as any
2970-
2971-
// Emit a separate reasoning item for the provider
2972-
cleanConversationHistory.push({
2973-
type: "reasoning",
2974-
summary: reasoningBlock.summary ?? [],
2975-
encrypted_content: reasoningBlock.encrypted_content,
2976-
...(reasoningBlock.id ? { id: reasoningBlock.id } : {}),
2977-
})
2978-
2979-
// Build assistant message without the embedded reasoning block
2980-
let assistantContent: Anthropic.Messages.MessageParam["content"]
2981-
2982-
if (rest.length === 0) {
2983-
assistantContent = ""
2984-
} else if (rest.length === 1 && rest[0].type === "text") {
2985-
assistantContent = (rest[0] as Anthropic.Messages.TextBlockParam).text
2986-
} else {
2987-
assistantContent = rest
2988-
}
2989-
2990-
cleanConversationHistory.push({
2991-
role: "assistant",
2992-
content: assistantContent,
2993-
} satisfies Anthropic.Messages.MessageParam)
2994-
2995-
continue
2996-
}
2997-
}
2998-
2999-
// Default path for regular messages (no embedded reasoning)
3000-
if (msg.role) {
3001-
cleanConversationHistory.push({
3002-
role: msg.role,
3003-
content: msg.content as Anthropic.Messages.ContentBlockParam[] | string,
3004-
})
3005-
}
3006-
}
2927+
const cleanConversationHistory = this.buildCleanConversationHistory(messagesWithoutImages as ApiMessage[])
30072928

30082929
// Check auto-approval limits
30092930
const approvalResult = await this.autoApprovalHandler.checkAutoApprovalLimits(
@@ -3235,6 +3156,91 @@ export class Task extends EventEmitter<TaskEvents> implements TaskLike {
32353156
return checkpointSave(this, force, suppressMessage)
32363157
}
32373158

3159+
private buildCleanConversationHistory(
3160+
messages: ApiMessage[],
3161+
): Array<
3162+
Anthropic.Messages.MessageParam | { type: "reasoning"; encrypted_content: string; id?: string; summary?: any[] }
3163+
> {
3164+
type ReasoningItemForRequest = {
3165+
type: "reasoning"
3166+
encrypted_content: string
3167+
id?: string
3168+
summary?: any[]
3169+
}
3170+
3171+
const cleanConversationHistory: (Anthropic.Messages.MessageParam | ReasoningItemForRequest)[] = []
3172+
3173+
for (const msg of messages) {
3174+
// Legacy path: standalone reasoning items stored as separate messages
3175+
if (msg.type === "reasoning" && msg.encrypted_content) {
3176+
cleanConversationHistory.push({
3177+
type: "reasoning",
3178+
summary: msg.summary,
3179+
encrypted_content: msg.encrypted_content!,
3180+
...(msg.id ? { id: msg.id } : {}),
3181+
})
3182+
continue
3183+
}
3184+
3185+
// Preferred path: assistant message with embedded reasoning as first content block
3186+
if (msg.role === "assistant") {
3187+
const rawContent = msg.content
3188+
3189+
const contentArray: Anthropic.Messages.ContentBlockParam[] = Array.isArray(rawContent)
3190+
? (rawContent as Anthropic.Messages.ContentBlockParam[])
3191+
: rawContent !== undefined
3192+
? ([
3193+
{ type: "text", text: rawContent } satisfies Anthropic.Messages.TextBlockParam,
3194+
] as Anthropic.Messages.ContentBlockParam[])
3195+
: []
3196+
3197+
const [first, ...rest] = contentArray
3198+
3199+
const hasEmbeddedReasoning =
3200+
first && (first as any).type === "reasoning" && typeof (first as any).encrypted_content === "string"
3201+
3202+
if (hasEmbeddedReasoning) {
3203+
const reasoningBlock = first as any
3204+
3205+
// Emit a separate reasoning item for the provider
3206+
cleanConversationHistory.push({
3207+
type: "reasoning",
3208+
summary: reasoningBlock.summary ?? [],
3209+
encrypted_content: reasoningBlock.encrypted_content,
3210+
...(reasoningBlock.id ? { id: reasoningBlock.id } : {}),
3211+
})
3212+
3213+
// Build assistant message without the embedded reasoning block
3214+
let assistantContent: Anthropic.Messages.MessageParam["content"]
3215+
3216+
if (rest.length === 0) {
3217+
assistantContent = ""
3218+
} else if (rest.length === 1 && rest[0].type === "text") {
3219+
assistantContent = (rest[0] as Anthropic.Messages.TextBlockParam).text
3220+
} else {
3221+
assistantContent = rest
3222+
}
3223+
3224+
cleanConversationHistory.push({
3225+
role: "assistant",
3226+
content: assistantContent,
3227+
} satisfies Anthropic.Messages.MessageParam)
3228+
3229+
continue
3230+
}
3231+
}
3232+
3233+
// Default path for regular messages (no embedded reasoning)
3234+
if (msg.role) {
3235+
cleanConversationHistory.push({
3236+
role: msg.role,
3237+
content: msg.content as Anthropic.Messages.ContentBlockParam[] | string,
3238+
})
3239+
}
3240+
}
3241+
3242+
return cleanConversationHistory
3243+
}
32383244
public async checkpointRestore(options: CheckpointRestoreOptions) {
32393245
return checkpointRestore(this, options)
32403246
}

0 commit comments

Comments
 (0)