char-slop/berry
multipurpose self-modifiable agentic harness
git clone https://git.t4t.associates/char-slop/berry
3339f51
main
1import type { JsonValue } from "@berry/api" ; 2import { code , type ToolRenderer , type ToolView } from "@berry/api/web.ts" ; 3import * as j from "@char/justin" ; 4import { ansiOutput } from "./ansi-view.ts" ; 5 6const argsOf = j . validation . compile ( 7j . obj ({ command :j . optional ( j . string ), timeout :j . optional ( j . number ) }), 8); 9const outputOf = j . validation . compile ( j . obj ({ output :j . string })); 10const rawOutputOf = j . validation . compile ( j . obj ({ rawOutput :j . string })); 11const exitCodeOf = j . validation . compile ( j . obj ({ exitCode :j . number })); 12 13export function bashView ( language = "bash" ) :ToolView { 14const prompt = < div class = "command" / >; 15const rendered = < pre hidden /> as HTMLPreElement ; 16const showOutput = ansiOutput ( rendered ); 17const exit = < span class = "exit" hidden / > as HTMLSpanElement; 18let shown :{ command :string ; streaming:boolean } | null = null ; 19return { 20element :( 21< div class = "tool-body" > 22{ prompt} 23{ rendered} 24{ exit} 25< / div> 26), 27update ( call ) { 28const args = argsOf ( call . args ). value ; 29const command = args ?. command ?? "" ; 30const streaming = call . status === "streaming" ; 31// highlighted once the model has written all of it 32if ( command !== shown ?. command || streaming !== shown . streaming ) { 33prompt . replaceChildren ( 34code ( command , { 35... ( streaming ? {} : { language }), 36gutter : ( i ) => ( i === 0 ? "$" : "" ), 37}), 38); 39} 40// a direct call's result is the text the model saw, which carries the exit code itself 41const result = call . result ; 42const output = ( typeof result === "string" ? result : outputOf ( result ). value ?. output ) ?? 43rawOutputOf ( call . details ). value ?. rawOutput ?? call . output ?? call . error ?? "" ; 44showOutput ( output ); 45shown = { command , streaming }; 46const exitCode = exitCodeOf ( result ). value ?. exitCode ; 47exit . textContent = exitCode === undefined || exitCode === 0 ? "" : `exit ${ exitCode } ` ; 48exit . hidden = exit . textContent === "" ; 49}, 50}; 51} 52 53/** The exit code a call ended with: in a script's result, or at the end of the text a direct call's model saw. */ 54function exitCode ( result : JsonValue | null ) : number | null { 55if ( typeof result === "string" ) { 56const code = result . match ( / \[exit code (-?\d+)(?:;[^\]]*)?\]\s*$ / )?.[ 1 ]; 57return code === undefined ? null : Number ( code ); 58} 59return exitCodeOf ( result ). value ?. exitCode ?? null ; 60} 61 62export const bashRenderer : ToolRenderer = { 63summary : ( args ) => argsOf ( args ). value ?. command ?. split ( "\n" )[ 0 ] ?? null , 64timeout : ( args ) => argsOf ( args ). value ?. timeout ?? null , 65outcome : ( call ) => { 66const code = exitCode ( call . result ); 67return code === null || code === 0 ? null : `exit ${ code } ` ; 68}, 69body : () => bashView (), 70}; 71 72export const powershellRenderer : ToolRenderer = { 73... bashRenderer , 74body : () => bashView ( "powershell" ), 75};