59 lines
4.4 KiB
TypeScript
59 lines
4.4 KiB
TypeScript
/** Real pi-ai API adapters, catalog metadata, live provider edits, and durable usage. */
|
|
import {configuredModels,resolveModel,modelCatalog,CONFIG} from './models';
|
|
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 fetch=globalThis.fetch;
|
|
globalThis.fetch=async()=>{throw new Error('offline')};
|
|
const catalog=await modelCatalog();
|
|
assert(catalog.openai.models['gpt-6.1-sol'],'packaged snapshot works offline');
|
|
await Deno.core.ops.op_model_catalog({...catalog,cache_fixture:{id:'cache_fixture',models:{}}});
|
|
assert((await modelCatalog()).cache_fixture.id==='cache_fixture','persisted metadata cache works offline');
|
|
await Deno.core.ops.op_model_catalog(catalog);
|
|
globalThis.fetch=fetch;
|
|
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');
|
|
assert(defaults.contextWindow===catalog.openai.models['gpt-6.1-sol'].limit.context,'catalog context default');
|
|
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});
|
|
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');
|