my harness for niri
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 60 lines 1.8 kB view raw
1import OpenAI from "openai" 2import type { LoopState } from "./types.js" 3import type { FunctionToolCall } from "./loop-shared.js" 4 5/** 6 * Normalizes assistant/tool message content into plain text. 7 * 8 * @param content - Raw OpenAI-compatible message content. 9 * @returns Trimmed text representation. 10 */ 11export function assistantContentText(content: unknown): string { 12 if (typeof content === "string") return content.trim() 13 if (!Array.isArray(content)) return "" 14 15 let combined = "" 16 for (const part of content) { 17 if (!part || typeof part !== "object") continue 18 const record = part as Record<string, unknown> 19 20 if (typeof record.text === "string") { 21 combined += record.text 22 continue 23 } 24 if ( 25 record.text && 26 typeof record.text === "object" && 27 "value" in record.text && 28 typeof (record.text as { value?: unknown }).value === "string" 29 ) { 30 combined += (record.text as { value: string }).value 31 } 32 } 33 34 return combined.trim() 35} 36 37/** 38 * Returns the most recent assistant message text from loop state. 39 * 40 * @param state - Mutable loop state. 41 * @returns Latest assistant text, or empty string when none exists. 42 */ 43export function latestAssistantContent(state: LoopState): string { 44 for (let i = state.conversation.length - 1; i >= 0; i--) { 45 const message = state.conversation[i] 46 if (!message || message.role !== "assistant") continue 47 return assistantContentText(message.content) 48 } 49 return "" 50} 51 52/** 53 * Type guard that narrows a tool call to function-call shape. 54 * 55 * @param call - Raw tool call from the assistant response. 56 * @returns `true` when the call is a function tool call. 57 */ 58export function isFunctionToolCall(call: OpenAI.Chat.ChatCompletionMessageToolCall): call is FunctionToolCall { 59 return call.type === "function" 60}