fix(thinking-block-validator): handle text content parts in message validation
Previously, the validator only checked for tool_use parts, causing 'Expected thinking but found text' errors when messages had text content. Renamed hasToolParts to hasContentParts to include both tool_use and text types. Also added CommentCheckerConfigSchema support for custom prompt configuration. 🤖 Generated with assistance of OhMyOpenCode (https://github.com/code-yeongyu/oh-my-opencode)
This commit is contained in:
@@ -115,6 +115,11 @@ export const SisyphusAgentConfigSchema = z.object({
|
||||
replace_plan: z.boolean().optional(),
|
||||
})
|
||||
|
||||
export const CommentCheckerConfigSchema = z.object({
|
||||
/** Custom prompt to replace the default warning message. Use {{comments}} placeholder for detected comments XML. */
|
||||
custom_prompt: z.string().optional(),
|
||||
})
|
||||
|
||||
export const DynamicContextPruningConfigSchema = z.object({
|
||||
/** Enable dynamic context pruning (default: false) */
|
||||
enabled: z.boolean().default(false),
|
||||
@@ -175,6 +180,7 @@ export const OhMyOpenCodeConfigSchema = z.object({
|
||||
claude_code: ClaudeCodeConfigSchema.optional(),
|
||||
google_auth: z.boolean().optional(),
|
||||
sisyphus_agent: SisyphusAgentConfigSchema.optional(),
|
||||
comment_checker: CommentCheckerConfigSchema.optional(),
|
||||
experimental: ExperimentalConfigSchema.optional(),
|
||||
auto_update: z.boolean().optional(),
|
||||
})
|
||||
@@ -185,6 +191,7 @@ export type AgentOverrides = z.infer<typeof AgentOverridesSchema>
|
||||
export type AgentName = z.infer<typeof AgentNameSchema>
|
||||
export type HookName = z.infer<typeof HookNameSchema>
|
||||
export type SisyphusAgentConfig = z.infer<typeof SisyphusAgentConfigSchema>
|
||||
export type CommentCheckerConfig = z.infer<typeof CommentCheckerConfigSchema>
|
||||
export type ExperimentalConfig = z.infer<typeof ExperimentalConfigSchema>
|
||||
export type DynamicContextPruningConfig = z.infer<typeof DynamicContextPruningConfigSchema>
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import type { PendingCall } from "./types"
|
||||
import { runCommentChecker, getCommentCheckerPath, startBackgroundInit, type HookInput } from "./cli"
|
||||
import type { CommentCheckerConfig } from "../../config/schema"
|
||||
|
||||
import * as fs from "fs"
|
||||
import { existsSync } from "fs"
|
||||
@@ -32,8 +33,8 @@ function cleanupOldPendingCalls(): void {
|
||||
|
||||
setInterval(cleanupOldPendingCalls, 10_000)
|
||||
|
||||
export function createCommentCheckerHooks() {
|
||||
debugLog("createCommentCheckerHooks called")
|
||||
export function createCommentCheckerHooks(config?: CommentCheckerConfig) {
|
||||
debugLog("createCommentCheckerHooks called", { config })
|
||||
|
||||
// Start background CLI initialization (may trigger lazy download)
|
||||
startBackgroundInit()
|
||||
@@ -123,7 +124,7 @@ export function createCommentCheckerHooks() {
|
||||
|
||||
// CLI mode only
|
||||
debugLog("using CLI:", cliPath)
|
||||
await processWithCli(input, pendingCall, output, cliPath)
|
||||
await processWithCli(input, pendingCall, output, cliPath, config?.custom_prompt)
|
||||
} catch (err) {
|
||||
debugLog("tool.execute.after failed:", err)
|
||||
}
|
||||
@@ -135,7 +136,8 @@ async function processWithCli(
|
||||
input: { tool: string; sessionID: string; callID: string },
|
||||
pendingCall: PendingCall,
|
||||
output: { output: string },
|
||||
cliPath: string
|
||||
cliPath: string,
|
||||
customPrompt?: string
|
||||
): Promise<void> {
|
||||
debugLog("using CLI mode with path:", cliPath)
|
||||
|
||||
@@ -154,7 +156,7 @@ async function processWithCli(
|
||||
},
|
||||
}
|
||||
|
||||
const result = await runCommentChecker(hookInput, cliPath)
|
||||
const result = await runCommentChecker(hookInput, cliPath, customPrompt)
|
||||
|
||||
if (result.hasComments && result.message) {
|
||||
debugLog("CLI detected comments, appending message")
|
||||
|
||||
@@ -51,14 +51,15 @@ function isExtendedThinkingModel(modelID: string): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a message has tool parts (tool_use)
|
||||
* Check if a message has any content parts (tool_use, text, or other non-thinking content)
|
||||
*/
|
||||
function hasToolParts(parts: Part[]): boolean {
|
||||
function hasContentParts(parts: Part[]): boolean {
|
||||
if (!parts || parts.length === 0) return false
|
||||
|
||||
return parts.some((part: Part) => {
|
||||
const type = part.type as string
|
||||
return type === "tool" || type === "tool_use"
|
||||
// Include tool parts and text parts (anything that's not thinking/reasoning)
|
||||
return type === "tool" || type === "tool_use" || type === "text"
|
||||
})
|
||||
}
|
||||
|
||||
@@ -154,8 +155,8 @@ export function createThinkingBlockValidatorHook(): MessagesTransformHook {
|
||||
// Only check assistant messages
|
||||
if (msg.info.role !== "assistant") continue
|
||||
|
||||
// Check if message has tool parts but doesn't start with thinking
|
||||
if (hasToolParts(msg.parts) && !startsWithThinkingBlock(msg.parts)) {
|
||||
// Check if message has content parts but doesn't start with thinking
|
||||
if (hasContentParts(msg.parts) && !startsWithThinkingBlock(msg.parts)) {
|
||||
// Find thinking content from previous turns
|
||||
const previousThinking = findPreviousThinkingContent(messages, i)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user