/** Real pi-ai API adapters, catalog metadata, live provider edits, and durable usage. */ import {configuredModels,resolveModel,modelCatalog,CONFIG} from './models'; import {getBuiltinModel} from '@earendil-works/pi-ai/providers/all'; import {fs} from './extensions'; import {environment} from './environment'; import {BACKGROUND_CONTEXT as context} from '@earendil-works/chord/context'; import {Harness,createRegistry} from '@earendil-works/pi-durable'; import {openStorage} from './sqlite'; import modelExtension from '../../extensions/models/server'; const assert=(ok:any,message:string)=>{if(!ok)throw new Error(message)}; const catalog=await modelCatalog(); let config=globalThis.providerSettings; const readProviders=()=>Deno.core.ops.op_model_providers(); const models=await configuredModels(readProviders,catalog); const defaults=models.getModel('responses','gpt-6.1-sol'); const sol=getBuiltinModel('openai','gpt-6.1-sol'); const opus=models.getModel('messages','claude-opus-5-5'); const opusCatalog=getBuiltinModel('anthropic','claude-opus-5-5'); assert(opus.compat?.forceAdaptiveThinking===true,'Opus 5.5 requires adaptive thinking'); assert(JSON.stringify(opus.thinkingLevelMap)===JSON.stringify(opusCatalog.thinkingLevelMap)&&opus.thinkingLevelMap,'Opus keeps its thinking level map'); assert(defaults.contextWindow===sol.contextWindow,'catalog context default'); assert(sol.cost.tiers?.length&&JSON.stringify(defaults.cost)===JSON.stringify(sol.cost),'Sol keeps its catalog price tiers'); const custom=resolveModel('anthropic-custom',{...config.providers.messages,catalog:'anthropic'},{id:'claude-opus-5-5',context_window:272000},catalog); assert(custom.contextWindow===272000&&custom.baseUrl===config.providers.messages.base_url,'custom provider overrides its context and URL'); for(const field of ['compat','thinkingLevelMap','promptCache','inputLimits','input','cost'])assert(JSON.stringify(custom[field])===JSON.stringify(opusCatalog[field]),`custom provider retains ${field}`); assert(custom.compat.forceAdaptiveThinking,'custom provider retains adaptive thinking'); const override=resolveModel('custom',{...config.providers.responses,catalog:'openai'},{id:'gpt-6.1-sol',context_window:272000},catalog); assert(override.contextWindow===272000&&override.maxTokens===defaults.maxTokens&&override.cost.input===defaults.cost.input,'context-only override preserves catalog values'); let failure=''; try{resolveModel('custom',config.providers.responses,'unknown-model',catalog)}catch(error){failure=String(error)} for(const text of [CONFIG,'custom/unknown-model','context_window','max_tokens','reasoning','cost.input'])assert(failure.includes(text),`unknown model names missing ${text}`); const supplied={id:'unknown-model',context_window:32000,max_tokens:4000,reasoning:false,cost:{input:1,output:2,cache_read:0,cache_write:0}}; assert(resolveModel('custom',config.providers.responses,supplied,catalog).cost.output===2,'unknown model accepts complete overrides'); for(const [provider,id] of [['messages','claude-opus-5-5'],['responses','gpt-6.1-sol'],['chat','gpt-6.1-sol']]){ const model=models.getModel(provider,id); const result=await models.completeSimple(model,{messages:[{role:'user',content:'Say hello.',timestamp:Date.now()}]},{maxTokens:128,reasoning:provider==='messages'?'high':undefined,onPayload:payload=>{ if(provider==='messages'){ assert(payload.thinking?.type==='adaptive','high thinking uses adaptive, not enabled'); assert(typeof payload.output_config?.effort==='string','adaptive thinking sets output_config.effort'); assert(payload.messages.some(message=>message.output_config?.effort==='high'),'high thinking uses the catalog mid-conversation effort marker'); } }}); assert(result.stopReason!=='error',`${provider}: ${result.errorMessage}`); assert(result.content.some(block=>block.type==='text'&&block.text==='hello'),`${provider}: streamed text`); assert(result.usage.cost.total>0,`${provider}: computed usage cost`); } await fs.mkdir('/etc/sausage/roster'); await fs.write('/etc/sausage/roster/main.md','---\ndescription: Main\nmodel: responses/gpt-6.1-sol\n---\nMain role'); const registry=createRegistry(); registry.install(modelExtension({fs,models:()=>models,implement:()=>{},want:()=>undefined})); const storage=await openStorage(globalThis.storagePath); const harness=await Harness.open(storage,{models,registry,env:()=>environment('/'),settings:{retry:{enabled:false},get extensions(){return registry.snapshot().installed()}}},context); const root=await harness.root(context,{agent:{cwd:'/',model:{provider:'responses',modelId:'gpt-6.1-sol'}}}); harness.resume(); try{ await (await root.submit({type:'input',content:'First run'},context)).wait(context); config.providers.responses.base_url=globalThis.providerBase+'/edited-api'; config.providers.responses.api_key='next-key'; config.providers.responses.models=[{id:'gpt-6.1-sol',context_window:272000}]; await fs.write(CONFIG,JSON.stringify(config)); await (await root.submit({type:'input',content:'Next run'},context)).wait(context); assert(models.getModel('responses','gpt-6.1-sol').contextWindow===272000,'provider metadata edit applies on the next run'); const entries=(await root.context(context)).entries.filter(entry=>entry.kind==='pi.assistant'); assert(entries.length===2&&entries.every(entry=>entry.model[0].usage.cost.total>0),'stored assistant usage includes call costs'); }finally{await harness.close(context);await storage.close()} config.providers.responses.api_key='';await fs.write(CONFIG,JSON.stringify(config)); failure='';try{await models.getAuth('responses')}catch(error){failure=String(error)} assert(failure.includes(CONFIG),'missing key identifies config file');