Files
sausage/host/js/automations-pause-fixture.ts
T

34 lines
3.2 KiB
TypeScript

/** Pause cases use snapshot modules and isolated durable storage, as Standing agent's fixture does. */
import { BACKGROUND_CONTEXT as context } from '@earendil-works/chord/context'
import { obj } from '@earendil-works/pi-schema'
import { createModels } from '@earendil-works/pi-ai/models'
import { fauxProvider } from '@earendil-works/pi-ai/providers/faux'
import { Harness,createRegistry,defineExtension,defineTask,defineTool } from '@earendil-works/pi-durable'
import { openStorage } from './sqlite'
import { Metadata } from './extensions'
let serial=0
export const hosts:any[]=[]
export const streamTask=(released:Promise<void>)=>defineTask({name:'pause-test.stream',version:1,initial:()=>({phase:'stream'}),phases:{stream:async(_task:any,runtime:any,ctx:any)=>{await released;await runtime.commit(()=>({status:'terminal',outcome:{status:'completed',result:null}}),ctx)}},abort:(_task:any,runtime:any,ctx:any)=>runtime.commit(()=>({status:'terminal',outcome:{status:'aborted'}}),ctx)})
export async function fixture(home?:string,retry:any={}) {
home??=`${globalThis.storagePath}.pause-${++serial}`
const registry=createRegistry(),models=createModels(),faux=fauxProvider({tokensPerSecond:100000});models.setProvider(faux.provider)
let finish:any,finished=0,opened:any,storage:any
const background=Promise.withResolvers<void>(),openers:any[]=[],closers:any[]=[],services=new Map(),resources=new Map()
registry.install(defineExtension({name:'pause-test',tasks:[streamTask(background.promise)],tools:[defineTool({name:'work',description:'Work until released',parameters:obj({}),execute:async()=>{await new Promise(resolve=>{finish=resolve});finished++;return {content:[{type:'text',text:'worked'}]}}})]}))
const host:any={harness:()=>opened.harness,metadata:Metadata,implement:(api:any,value:any)=>services.set(api.name,value),want:(api:any)=>services.get(api.name),resource:(key:string,create:any)=>{if(!resources.has(key))resources.set(key,create());return resources.get(key)},onOpen:(cb:any)=>openers.push(cb),onClose:(cb:any)=>closers.push(cb)}
const module=await import(/* @vite-ignore */ `${globalThis.automationBase}/pause/server.ts`)
registry.install(module.default(host))
const open=async()=>{
storage=await openStorage(home!)
const harness=await Harness.open(storage,{models,registry,settings:{retry:{baseDelayMs:1,...retry},get extensions(){return registry.snapshot().installed()}}},context)
const root=await harness.root(context,{agent:{model:{provider:'faux',modelId:'faux-1'}}})
opened={harness,root,close:async()=>{for(const cb of closers)await cb();await harness.close(context);await storage.close()}}
hosts.push(opened)
for(const cb of openers)await cb()
harness.resume()
return opened
}
return {home,prepared:{registry,faux},open,action:(name:string)=>module.actions[name](null,{host}),setAutoPlay:(minutes:number|null)=>module.actions.autoPlay({minutes},{host}),autoPlay:(now:number)=>module.autoPlay(host,now),paused:()=>services.get('pause').paused(),get opened(){return opened},get finish(){return finish},finished:()=>finished,background,stream:streamTask(background.promise),close:async()=>{await opened.close();hosts.splice(hosts.indexOf(opened),1)}}
}
export async function clean() {for(const host of hosts.splice(0))await host.close()}