feat(workflow): ThreadReactor — generic ReAct loop + extract/supervisor migration #142
Reference in New Issue
Block a user
Delete Branch "feat/139-thread-reactor"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What
Introduce
ThreadReactor— a generic two-stage ReAct loop for thread-scoped LLM interactions.Changes
Phase 1: ThreadReactor core + extract migration
src/reactor/module:createThreadReactor,createLlmFn, typesLlmFnabstraction: reactor never touches HTTP/fetchcreateExtractto usecreateThreadReactorreactExtractimplementationPhase 2: Supervisor migration
createThreadReactor+createLlmFnBreaking Changes
reactExtract/ReactExtractArgsremoved from public APIcreateThreadReactorinsteadVerification
bun run checkcleanFixes #139
Relates #140 #141
Review: ThreadReactor ✅
17 files, +748/-566。RFC #139 决议全部落地,重构干净。
✅ 亮点
ThreadReactorConfig(创建时固定 llm/tools/systemPrompt)+ per-callthread/input/schema。TThread泛型让 extract 传{cas}、supervisor 传Record<string,never>都类型安全createLlmFn封装 fetch,测试 mock 干净parseSupervisorDecisionText) 迁移到 zod schema{decision: 'continue'|'stop'},删了脆弱的字符串解析。大改进structuredToolFromSchema+systemPromptForStructuredTool分离:system prompt 引用 tool name,maximizes prefix cache hit。设计到位react-extract.ts343 行删光,ReactExtractArgs从 public API 移除,不留遗产💡 Nits(不阻塞)
Dashboard key 回归(thread-detail.tsx):上次 review 改成
key={i},这个 PR 又改成key={threadId-type-timestamp-role-content}拼接字符串。比 JSON.stringify 好但仍有开销,而且两条内容完全相同的 record 会 key 碰撞。考虑用 SSE event id 或 indexLlmFn返回 raw response text(而非 parsed message):调用方每次都要firstAssistantMessage(bodyResult.value)手动解析。如果让 LlmFn 返回Result<AssistantMessage, string>可以把解析逻辑下沉。但当前设计也说得通(LlmFn 职责最小化),看团队偏好LGTM 🫡