@directive-run/ai 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/anthropic.cjs +1 -1
- package/dist/anthropic.cjs.map +1 -1
- package/dist/anthropic.js +1 -1
- package/dist/anthropic.js.map +1 -1
- package/dist/{chunk-265ZKXYE.js → chunk-3PGRBK4E.js} +2 -2
- package/dist/chunk-3PGRBK4E.js.map +1 -0
- package/dist/{chunk-QXMXSHYS.cjs → chunk-KP3G32S7.cjs} +2 -2
- package/dist/chunk-KP3G32S7.cjs.map +1 -0
- package/dist/{chunk-5ERCL33C.js → chunk-Q3PQLWBR.js} +3 -3
- package/dist/chunk-Q3PQLWBR.js.map +1 -0
- package/dist/{chunk-K2LZMRLN.js → chunk-RW4R3O5P.js} +3 -3
- package/dist/{chunk-K2LZMRLN.js.map → chunk-RW4R3O5P.js.map} +1 -1
- package/dist/{chunk-KALRDVN5.cjs → chunk-X3VQ5F7D.cjs} +3 -3
- package/dist/{chunk-KALRDVN5.cjs.map → chunk-X3VQ5F7D.cjs.map} +1 -1
- package/dist/{chunk-L35IQAWD.cjs → chunk-XV2QSBBE.cjs} +7 -7
- package/dist/chunk-XV2QSBBE.cjs.map +1 -0
- package/dist/gemini.cjs +1 -1
- package/dist/gemini.cjs.map +1 -1
- package/dist/gemini.js +1 -1
- package/dist/gemini.js.map +1 -1
- package/dist/index.cjs +18 -18
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -6
- package/dist/index.d.ts +50 -6
- package/dist/index.js +18 -18
- package/dist/index.js.map +1 -1
- package/dist/{multi-agent-orchestrator-675FR2HF.js → multi-agent-orchestrator-4PXNYRHB.js} +2 -2
- package/dist/{multi-agent-orchestrator-675FR2HF.js.map → multi-agent-orchestrator-4PXNYRHB.js.map} +1 -1
- package/dist/multi-agent-orchestrator-KFGTEGE5.cjs +2 -0
- package/dist/{multi-agent-orchestrator-SH5TRRS3.cjs.map → multi-agent-orchestrator-KFGTEGE5.cjs.map} +1 -1
- package/dist/ollama.cjs +2 -2
- package/dist/ollama.cjs.map +1 -1
- package/dist/ollama.js +1 -1
- package/dist/ollama.js.map +1 -1
- package/dist/openai.cjs +1 -1
- package/dist/openai.cjs.map +1 -1
- package/dist/openai.js +1 -1
- package/dist/openai.js.map +1 -1
- package/dist/{orchestrator-types-BmvoZgfO.d.cts → orchestrator-types-Bh8r3_Sq.d.cts} +1 -1
- package/dist/{orchestrator-types-D6gzobwg.d.ts → orchestrator-types-CTfIKk0W.d.ts} +1 -1
- package/dist/testing.cjs +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/package.json +2 -2
- package/dist/chunk-265ZKXYE.js.map +0 -1
- package/dist/chunk-5ERCL33C.js.map +0 -1
- package/dist/chunk-L35IQAWD.cjs.map +0 -1
- package/dist/chunk-QXMXSHYS.cjs.map +0 -1
- package/dist/multi-agent-orchestrator-SH5TRRS3.cjs +0 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export{Z as Semaphore,ua as aggregateTokens,ka as allReadyStrategy,xa as capabilityRoute,ta as collectOutputs,va as composePatterns,ra as concatResults,ma as costEfficientStrategy,Da as createMultiAgentOrchestrator,ga as dag,za as debate,Ba as derivedConstraint,aa as diffCheckpoints,wa as findAgentsByCapability,ba as forkFromCheckpoint,$ as getCheckpointProgress,_ as getPatternStep,ja as goal,la as highestImpactStrategy,da as parallel,oa as patternFromJSON,na as patternToJSON,sa as pickBestResult,ia as race,ha as reflect,qa as runAgentRequirement,Aa as runDebate,pa as selectAgent,ea as sequential,Y as shallowEqual,ya as spawnOnCondition,Ca as spawnPool,fa as supervisor,ca as validateDagAcyclic}from'./chunk-
|
|
2
|
-
//# sourceMappingURL=multi-agent-orchestrator-
|
|
1
|
+
export{Z as Semaphore,ua as aggregateTokens,ka as allReadyStrategy,xa as capabilityRoute,ta as collectOutputs,va as composePatterns,ra as concatResults,ma as costEfficientStrategy,Da as createMultiAgentOrchestrator,ga as dag,za as debate,Ba as derivedConstraint,aa as diffCheckpoints,wa as findAgentsByCapability,ba as forkFromCheckpoint,$ as getCheckpointProgress,_ as getPatternStep,ja as goal,la as highestImpactStrategy,da as parallel,oa as patternFromJSON,na as patternToJSON,sa as pickBestResult,ia as race,ha as reflect,qa as runAgentRequirement,Aa as runDebate,pa as selectAgent,ea as sequential,Y as shallowEqual,ya as spawnOnCondition,Ca as spawnPool,fa as supervisor,ca as validateDagAcyclic}from'./chunk-RW4R3O5P.js';//# sourceMappingURL=multi-agent-orchestrator-4PXNYRHB.js.map
|
|
2
|
+
//# sourceMappingURL=multi-agent-orchestrator-4PXNYRHB.js.map
|
package/dist/{multi-agent-orchestrator-675FR2HF.js.map → multi-agent-orchestrator-4PXNYRHB.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"multi-agent-orchestrator-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"multi-agent-orchestrator-4PXNYRHB.js"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
'use strict';var chunkX3VQ5F7D_cjs=require('./chunk-X3VQ5F7D.cjs');Object.defineProperty(exports,"Semaphore",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.Z}});Object.defineProperty(exports,"aggregateTokens",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ua}});Object.defineProperty(exports,"allReadyStrategy",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ka}});Object.defineProperty(exports,"capabilityRoute",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.xa}});Object.defineProperty(exports,"collectOutputs",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ta}});Object.defineProperty(exports,"composePatterns",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.va}});Object.defineProperty(exports,"concatResults",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ra}});Object.defineProperty(exports,"costEfficientStrategy",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ma}});Object.defineProperty(exports,"createMultiAgentOrchestrator",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.Da}});Object.defineProperty(exports,"dag",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ga}});Object.defineProperty(exports,"debate",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.za}});Object.defineProperty(exports,"derivedConstraint",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.Ba}});Object.defineProperty(exports,"diffCheckpoints",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.aa}});Object.defineProperty(exports,"findAgentsByCapability",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.wa}});Object.defineProperty(exports,"forkFromCheckpoint",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ba}});Object.defineProperty(exports,"getCheckpointProgress",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.$}});Object.defineProperty(exports,"getPatternStep",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs._}});Object.defineProperty(exports,"goal",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ja}});Object.defineProperty(exports,"highestImpactStrategy",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.la}});Object.defineProperty(exports,"parallel",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.da}});Object.defineProperty(exports,"patternFromJSON",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.oa}});Object.defineProperty(exports,"patternToJSON",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.na}});Object.defineProperty(exports,"pickBestResult",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.sa}});Object.defineProperty(exports,"race",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ia}});Object.defineProperty(exports,"reflect",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ha}});Object.defineProperty(exports,"runAgentRequirement",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.qa}});Object.defineProperty(exports,"runDebate",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.Aa}});Object.defineProperty(exports,"selectAgent",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.pa}});Object.defineProperty(exports,"sequential",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ea}});Object.defineProperty(exports,"shallowEqual",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.Y}});Object.defineProperty(exports,"spawnOnCondition",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ya}});Object.defineProperty(exports,"spawnPool",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.Ca}});Object.defineProperty(exports,"supervisor",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.fa}});Object.defineProperty(exports,"validateDagAcyclic",{enumerable:true,get:function(){return chunkX3VQ5F7D_cjs.ca}});//# sourceMappingURL=multi-agent-orchestrator-KFGTEGE5.cjs.map
|
|
2
|
+
//# sourceMappingURL=multi-agent-orchestrator-KFGTEGE5.cjs.map
|
package/dist/{multi-agent-orchestrator-SH5TRRS3.cjs.map → multi-agent-orchestrator-KFGTEGE5.cjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"names":[],"mappings":"","file":"multi-agent-orchestrator-
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"multi-agent-orchestrator-KFGTEGE5.cjs"}
|
package/dist/ollama.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var
|
|
2
|
-
`);R=x.pop()??"";for(let H of x){let T=H.trim();if(!T)continue;let d;try{d=JSON.parse(T);}catch{typeof process<"u"&&process.env?.NODE_ENV==="development"&&console.warn("[Directive] Malformed streaming chunk from Ollama:",T);continue}let S=d.message?.content??"";S&&(h+=S,o.onToken?.(S)),d.done&&(y=d.prompt_eval_count??0,w=d.eval_count??0);}}}finally{l.cancel().catch(()=>{});}let _={inputTokens:y,outputTokens:w},P=y+w;return o.onMessage?.({role:"assistant",content:h}),
|
|
1
|
+
'use strict';var chunkKP3G32S7_cjs=require('./chunk-KP3G32S7.cjs'),chunkW6MVJKWN_cjs=require('./chunk-W6MVJKWN.cjs');var J={llama3:{input:0,output:0},"llama3.1":{input:0,output:0},"llama3.2":{input:0,output:0},"llama3.3":{input:0,output:0},mistral:{input:0,output:0},mixtral:{input:0,output:0},codellama:{input:0,output:0},gemma2:{input:0,output:0},phi3:{input:0,output:0},qwen2:{input:0,output:0},deepseek:{input:0,output:0},"deepseek-coder":{input:0,output:0},"command-r":{input:0,output:0}};function B(b={}){let{model:k="llama3",baseURL:a="http://localhost:11434",fetch:O=globalThis.fetch,timeoutMs:i,hooks:f,temperature:p,topP:c,stop:m,numPredict:n}=b;chunkW6MVJKWN_cjs.d(a);let r={};p!=null&&(r.temperature=p),c!=null&&(r.top_p=c),m!=null&&(r.stop=m),n!=null&&(r.num_predict=n);let s=Object.keys(r).length>0;return chunkW6MVJKWN_cjs.e({fetch:O,hooks:f,buildRequest:(e,o,u)=>({url:`${a}/api/chat`,init:{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:e.model??k,messages:[...e.instructions?[{role:"system",content:e.instructions}]:[],...u.map(t=>({role:t.role,content:t.content}))],stream:false,...s?{options:r}:{}}),...i!=null?{signal:AbortSignal.timeout(i)}:{}}}),parseResponse:async e=>{let o;try{o=await e.json();}catch{throw new Error(`[Directive] Ollama returned non-JSON response. Is Ollama running at ${a}? Start it with: ollama serve`)}let u=o.message?.content??"",t=o.prompt_eval_count??0,l=o.eval_count??0;return {text:u,totalTokens:t+l,inputTokens:t,outputTokens:l}}})}function I(b={}){let{model:k="llama3",baseURL:a="http://localhost:11434",fetch:O=globalThis.fetch,hooks:i,temperature:f,topP:p,stop:c,numPredict:m}=b;chunkW6MVJKWN_cjs.d(a);let n={};f!=null&&(n.temperature=f),p!=null&&(n.top_p=p),c!=null&&(n.stop=c),m!=null&&(n.num_predict=m);let r=Object.keys(n).length>0;return async(s,e,o)=>{let u=chunkKP3G32S7_cjs.e(i,s,e);try{let t=await O(`${a}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:s.model??k,messages:[...s.instructions?[{role:"system",content:s.instructions}]:[],{role:"user",content:e}],stream:!0,...r?{options:n}:{}}),signal:o.signal});if(!t.ok){let g=await t.text().catch(()=>"");throw new Error(`[Directive] Ollama streaming error ${t.status}${g?` \u2013 ${g.slice(0,200)}`:""}`)}let l=t.body?.getReader();if(!l)throw new Error("[Directive] No response body from Ollama");let D=new TextDecoder,R="",h="",y=0,w=0;try{for(;;){let{done:g,value:E}=await l.read();if(g)break;R+=D.decode(E,{stream:!0});let x=R.split(`
|
|
2
|
+
`);R=x.pop()??"";for(let H of x){let T=H.trim();if(!T)continue;let d;try{d=JSON.parse(T);}catch{typeof process<"u"&&process.env?.NODE_ENV==="development"&&console.warn("[Directive] Malformed streaming chunk from Ollama:",T);continue}let S=d.message?.content??"";S&&(h+=S,o.onToken?.(S)),d.done&&(y=d.prompt_eval_count??0,w=d.eval_count??0);}}}finally{l.cancel().catch(()=>{});}let _={inputTokens:y,outputTokens:w},P=y+w;return o.onMessage?.({role:"assistant",content:h}),chunkKP3G32S7_cjs.f(i,s,e,h,P,_,u),chunkKP3G32S7_cjs.h(e,h,P,_)}catch(t){throw chunkKP3G32S7_cjs.g(i,s,e,t,u),t}}}exports.OLLAMA_PRICING=J;exports.createOllamaRunner=B;exports.createOllamaStreamingRunner=I;//# sourceMappingURL=ollama.cjs.map
|
|
3
3
|
//# sourceMappingURL=ollama.cjs.map
|
package/dist/ollama.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/ollama.ts"],"names":["OLLAMA_PRICING","createOllamaRunner","options","model","baseURL","fetchFn","timeoutMs","hooks","temperature","topP","stop","numPredict","validateBaseURL","ollamaOptions","hasOptions","createRunner","agent","_input","messages","m","res","data","text","inputTokens","outputTokens","createOllamaStreamingRunner","input","callbacks","startTime","fireBeforeCallHook","response","errBody","reader","decoder","buf","fullText","done","value","lines","line","trimmed","chunk","content","tokenUsage","totalTokens","fireAfterCallHook","buildStreamingResult","err","fireErrorHook"],"mappings":"qHAmDO,IAAMA,CAAAA,CACX,CACE,MAAA,CAAQ,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAC9B,UAAA,CAAY,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAClC,UAAA,CAAY,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAClC,UAAA,CAAY,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAClC,OAAA,CAAS,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAC/B,OAAA,CAAS,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAC/B,SAAA,CAAW,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CACjC,MAAA,CAAU,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAChC,IAAA,CAAM,CAAE,KAAA,CAAO,CAAA,CAAG,OAAQ,CAAE,CAAA,CAC5B,KAAA,CAAO,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAC7B,QAAA,CAAU,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CAChC,iBAAkB,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CAAA,CACxC,WAAA,CAAa,CAAE,KAAA,CAAO,CAAA,CAAG,MAAA,CAAQ,CAAE,CACrC,EAyCK,SAASC,CAAAA,CACdC,EAA+B,EAAC,CACnB,CACb,GAAM,CACJ,KAAA,CAAAC,CAAAA,CAAQ,QAAA,CACR,OAAA,CAAAC,CAAAA,CAAU,wBAAA,CACV,KAAA,CAAOC,CAAAA,CAAU,UAAA,CAAW,KAAA,CAC5B,SAAA,CAAAC,EACA,KAAA,CAAAC,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,IAAA,CAAAC,CAAAA,CACA,IAAA,CAAAC,CAAAA,CACA,UAAA,CAAAC,CACF,CAAA,CAAIT,CAAAA,CAEJU,mBAAAA,CAAgBR,CAAO,CAAA,CAEvB,IAAMS,EAAyC,EAAC,CAC5CL,CAAAA,EAAe,IAAA,GACjBK,CAAAA,CAAc,WAAA,CAAcL,CAAAA,CAAAA,CAE1BC,CAAAA,EAAQ,IAAA,GACVI,CAAAA,CAAc,KAAA,CAAQJ,CAAAA,CAAAA,CAEpBC,CAAAA,EAAQ,IAAA,GACVG,CAAAA,CAAc,IAAA,CAAOH,CAAAA,CAAAA,CAEnBC,CAAAA,EAAc,IAAA,GAChBE,CAAAA,CAAc,WAAA,CAAcF,CAAAA,CAAAA,CAE9B,IAAMG,CAAAA,CAAa,MAAA,CAAO,IAAA,CAAKD,CAAa,CAAA,CAAE,MAAA,CAAS,CAAA,CAEvD,OAAOE,mBAAAA,CAAa,CAClB,KAAA,CAAOV,CAAAA,CACP,KAAA,CAAAE,CAAAA,CACA,YAAA,CAAc,CAACS,CAAAA,CAAOC,CAAAA,CAAQC,CAAAA,IAAc,CAC1C,GAAA,CAAK,CAAA,EAAGd,CAAO,CAAA,SAAA,CAAA,CACf,IAAA,CAAM,CACJ,OAAQ,MAAA,CACR,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAA,CAC9C,IAAA,CAAM,IAAA,CAAK,SAAA,CAAU,CACnB,KAAA,CAAOY,CAAAA,CAAM,KAAA,EAASb,CAAAA,CACtB,QAAA,CAAU,CACR,GAAIa,CAAAA,CAAM,YAAA,CACN,CAAC,CAAE,IAAA,CAAM,QAAA,CAAU,OAAA,CAASA,CAAAA,CAAM,YAAa,CAAC,CAAA,CAChD,EAAC,CACL,GAAGE,CAAAA,CAAS,GAAA,CAAKC,IAAO,CAAE,IAAA,CAAMA,CAAAA,CAAE,IAAA,CAAM,OAAA,CAASA,CAAAA,CAAE,OAAQ,CAAA,CAAE,CAC/D,CAAA,CACA,MAAA,CAAQ,KAAA,CACR,GAAIL,CAAAA,CAAa,CAAE,OAAA,CAASD,CAAc,CAAA,CAAI,EAChD,CAAC,CAAA,CACD,GAAIP,CAAAA,EAAa,IAAA,CACb,CAAE,MAAA,CAAQ,WAAA,CAAY,OAAA,CAAQA,CAAS,CAAE,CAAA,CACzC,EACN,CACF,CAAA,CAAA,CACA,aAAA,CAAe,MAAOc,CAAAA,EAAQ,CAC5B,IAAIC,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAO,MAAMD,CAAAA,CAAI,IAAA,GACnB,CAAA,KAAQ,CACN,MAAM,IAAI,KAAA,CACR,CAAA,oEAAA,EAAuEhB,CAAO,CAAA,6BAAA,CAChF,CACF,CACA,IAAMkB,CAAAA,CACFD,CAAAA,CAAK,OAAA,EAAqC,OAAA,EAAsB,EAAA,CAC9DE,CAAAA,CAAeF,CAAAA,CAAK,iBAAA,EAAgC,CAAA,CACpDG,CAAAA,CAAgBH,CAAAA,CAAK,UAAA,EAAyB,CAAA,CAEpD,OAAO,CACL,IAAA,CAAAC,CAAAA,CACA,WAAA,CAAaC,CAAAA,CAAcC,CAAAA,CAC3B,WAAA,CAAAD,CAAAA,CACA,YAAA,CAAAC,CACF,CACF,CACF,CAAC,CACH,CAuCO,SAASC,CAAAA,CACdvB,CAAAA,CAAwC,EAAC,CAChB,CACzB,GAAM,CACJ,KAAA,CAAAC,CAAAA,CAAQ,QAAA,CACR,QAAAC,CAAAA,CAAU,wBAAA,CACV,KAAA,CAAOC,CAAAA,CAAU,UAAA,CAAW,KAAA,CAC5B,KAAA,CAAAE,CAAAA,CACA,WAAA,CAAAC,CAAAA,CACA,IAAA,CAAAC,CAAAA,CACA,IAAA,CAAAC,CAAAA,CACA,UAAA,CAAAC,CACF,EAAIT,CAAAA,CAEJU,mBAAAA,CAAgBR,CAAO,CAAA,CAEvB,IAAMS,CAAAA,CAAyC,EAAC,CAC5CL,CAAAA,EAAe,IAAA,GACjBK,CAAAA,CAAc,WAAA,CAAcL,CAAAA,CAAAA,CAE1BC,CAAAA,EAAQ,IAAA,GACVI,CAAAA,CAAc,MAAQJ,CAAAA,CAAAA,CAEpBC,CAAAA,EAAQ,IAAA,GACVG,CAAAA,CAAc,IAAA,CAAOH,CAAAA,CAAAA,CAEnBC,CAAAA,EAAc,IAAA,GAChBE,CAAAA,CAAc,WAAA,CAAcF,CAAAA,CAAAA,CAE9B,IAAMG,CAAAA,CAAa,MAAA,CAAO,IAAA,CAAKD,CAAa,EAAE,MAAA,CAAS,CAAA,CAEvD,OAAO,MAAOG,CAAAA,CAAOU,CAAAA,CAAOC,CAAAA,GAAc,CACxC,IAAMC,CAAAA,CAAYC,mBAAAA,CAAmBtB,CAAAA,CAAOS,CAAAA,CAAOU,CAAK,CAAA,CAExD,GAAI,CACF,IAAMI,CAAAA,CAAW,MAAMzB,CAAAA,CAAQ,CAAA,EAAGD,CAAO,CAAA,SAAA,CAAA,CAAa,CACpD,MAAA,CAAQ,MAAA,CACR,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAA,CAC9C,IAAA,CAAM,KAAK,SAAA,CAAU,CACnB,KAAA,CAAOY,CAAAA,CAAM,KAAA,EAASb,CAAAA,CACtB,QAAA,CAAU,CACR,GAAIa,CAAAA,CAAM,YAAA,CACN,CAAC,CAAE,IAAA,CAAM,QAAA,CAAU,OAAA,CAASA,EAAM,YAAa,CAAC,CAAA,CAChD,EAAC,CACL,CAAE,IAAA,CAAM,MAAA,CAAQ,OAAA,CAASU,CAAM,CACjC,CAAA,CACA,MAAA,CAAQ,CAAA,CAAA,CACR,GAAIZ,CAAAA,CAAa,CAAE,OAAA,CAASD,CAAc,CAAA,CAAI,EAChD,CAAC,CAAA,CACD,MAAA,CAAQc,CAAAA,CAAU,MACpB,CAAC,CAAA,CAED,GAAI,CAACG,CAAAA,CAAS,EAAA,CAAI,CAChB,IAAMC,CAAAA,CAAU,MAAMD,CAAAA,CAAS,IAAA,EAAK,CAAE,KAAA,CAAM,IAAM,EAAE,CAAA,CAEpD,MAAM,IAAI,KAAA,CACR,CAAA,mCAAA,EAAsCA,CAAAA,CAAS,MAAM,GAAGC,CAAAA,CAAU,CAAA,QAAA,EAAMA,CAAAA,CAAQ,KAAA,CAAM,CAAA,CAAG,GAAG,CAAC,CAAA,CAAA,CAAK,EAAE,CAAA,CACtG,CACF,CAEA,IAAMC,CAAAA,CAASF,CAAAA,CAAS,IAAA,EAAM,WAAU,CACxC,GAAI,CAACE,CAAAA,CACH,MAAM,IAAI,KAAA,CAAM,0CAA0C,CAAA,CAG5D,IAAMC,CAAAA,CAAU,IAAI,WAAA,CAChBC,CAAAA,CAAM,EAAA,CACNC,CAAAA,CAAW,GACXZ,CAAAA,CAAc,CAAA,CACdC,CAAAA,CAAe,CAAA,CAEnB,GAAI,CACF,OAAa,CACX,GAAM,CAAE,IAAA,CAAAY,CAAAA,CAAM,KAAA,CAAAC,CAAM,CAAA,CAAI,MAAML,EAAO,IAAA,EAAK,CAC1C,GAAII,CAAAA,CACF,MAGFF,CAAAA,EAAOD,CAAAA,CAAQ,MAAA,CAAOI,CAAAA,CAAO,CAAE,MAAA,CAAQ,CAAA,CAAK,CAAC,CAAA,CAC7C,IAAMC,CAAAA,CAAQJ,EAAI,KAAA,CAAM;AAAA,CAAI,CAAA,CAC5BA,CAAAA,CAAMI,CAAAA,CAAM,GAAA,EAAI,EAAK,EAAA,CAErB,IAAA,IAAWC,CAAAA,IAAQD,CAAAA,CAAO,CACxB,IAAME,CAAAA,CAAUD,CAAAA,CAAK,IAAA,EAAK,CAC1B,GAAI,CAACC,CAAAA,CACH,SAGF,IAAIC,CAAAA,CACJ,GAAI,CACFA,CAAAA,CAAQ,IAAA,CAAK,KAAA,CAAMD,CAAO,EAC5B,MAAQ,CAEJ,OAAO,OAAA,CAAY,GAAA,EACnB,OAAA,CAAQ,GAAA,EAAK,QAAA,GAAa,aAAA,EAE1B,OAAA,CAAQ,IAAA,CACN,oDAAA,CACAA,CACF,CAAA,CAGF,QACF,CAKA,IAAME,CAAAA,CAHMD,CAAAA,CAAM,OAAA,EAGI,OAAA,EAAsB,EAAA,CACxCC,CAAAA,GACFP,CAAAA,EAAYO,CAAAA,CACZf,CAAAA,CAAU,OAAA,GAAUe,CAAO,CAAA,CAAA,CAGzBD,CAAAA,CAAM,IAAA,GACRlB,CAAAA,CACGkB,CAAAA,CAAM,mBAAgC,CAAA,CACzCjB,CAAAA,CAAgBiB,CAAAA,CAAM,UAAA,EAAyB,CAAA,EAEnD,CACF,CACF,CAAA,OAAE,CACAT,CAAAA,CAAO,MAAA,EAAO,CAAE,KAAA,CAAM,IAAM,CAAC,CAAC,EAChC,CAEA,IAAMW,CAAAA,CAAa,CAAE,WAAA,CAAApB,CAAAA,CAAa,YAAA,CAAAC,CAAa,CAAA,CACzCoB,CAAAA,CAAcrB,CAAAA,CAAcC,CAAAA,CAElC,OAAAG,CAAAA,CAAU,SAAA,GAAY,CAAE,IAAA,CAAM,WAAA,CAAa,OAAA,CAASQ,CAAS,CAAC,CAAA,CAC9DU,mBAAAA,CAAkBtC,CAAAA,CAAOS,CAAAA,CAAOU,CAAAA,CAAOS,CAAAA,CAAUS,CAAAA,CAAaD,CAAAA,CAAYf,CAAS,CAAA,CAE5EkB,mBAAAA,CAAqBpB,EAAOS,CAAAA,CAAUS,CAAAA,CAAaD,CAAU,CACtE,CAAA,MAASI,CAAAA,CAAK,CACZ,MAAAC,mBAAAA,CAAczC,CAAAA,CAAOS,CAAAA,CAAOU,CAAAA,CAAOqB,CAAAA,CAAKnB,CAAS,CAAA,CAE3CmB,CACR,CACF,CACF","file":"ollama.cjs","sourcesContent":["/**\n * @directive-run/ai/ollama\n *\n * Ollama adapter for Directive AI. Provides runners for local\n * Ollama inference. No API key required.\n *\n * Requires Ollama to be running locally. Start it with: `ollama serve`\n *\n * @example\n * ```typescript\n * import { createOllamaRunner } from '@directive-run/ai/ollama';\n *\n * const runner = createOllamaRunner({ model: 'llama3' });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type {\n AdapterHooks,\n AgentRunner,\n} from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\nimport {\n buildStreamingResult,\n fireAfterCallHook,\n fireBeforeCallHook,\n fireErrorHook,\n} from \"./shared.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Ollama model pricing (USD per million tokens).\n *\n * Ollama runs locally — all costs are zero. This table is provided for\n * compatibility with `estimateCost()` so local models integrate seamlessly\n * into cost-tracking pipelines.\n *\n * @example\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { OLLAMA_PRICING } from '@directive-run/ai/ollama';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, OLLAMA_PRICING[\"llama3\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, OLLAMA_PRICING[\"llama3\"].output);\n * // → 0\n * ```\n */\nexport const OLLAMA_PRICING: Record<string, { input: number; output: number }> =\n {\n llama3: { input: 0, output: 0 },\n \"llama3.1\": { input: 0, output: 0 },\n \"llama3.2\": { input: 0, output: 0 },\n \"llama3.3\": { input: 0, output: 0 },\n mistral: { input: 0, output: 0 },\n mixtral: { input: 0, output: 0 },\n codellama: { input: 0, output: 0 },\n \"gemma2\": { input: 0, output: 0 },\n phi3: { input: 0, output: 0 },\n qwen2: { input: 0, output: 0 },\n deepseek: { input: 0, output: 0 },\n \"deepseek-coder\": { input: 0, output: 0 },\n \"command-r\": { input: 0, output: 0 },\n };\n\n// ============================================================================\n// Ollama Runner\n// ============================================================================\n\n/** Options for createOllamaRunner */\nexport interface OllamaRunnerOptions {\n model?: string;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default undefined */\n timeoutMs?: number;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature. Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Stop sequences. The model will stop generating when it encounters one. */\n stop?: string[];\n /** Maximum number of tokens to generate. Ollama uses `num_predict`. */\n numPredict?: number;\n}\n\n/**\n * Create an AgentRunner for local Ollama inference.\n *\n * Ollama runs locally – no API key or cloud service needed. Default model\n * is `llama3`, default base URL is `http://localhost:11434`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking\n * (useful for monitoring local resource usage).\n *\n * @example\n * ```typescript\n * const runner = createOllamaRunner({ model: \"llama3\" });\n * const orchestrator = createAgentOrchestrator({ runner });\n * const result = await orchestrator.run(agent, input);\n * ```\n */\nexport function createOllamaRunner(\n options: OllamaRunnerOptions = {},\n): AgentRunner {\n const {\n model = \"llama3\",\n baseURL = \"http://localhost:11434\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n hooks,\n temperature,\n topP,\n stop,\n numPredict,\n } = options;\n\n validateBaseURL(baseURL);\n\n const ollamaOptions: Record<string, unknown> = {};\n if (temperature != null) {\n ollamaOptions.temperature = temperature;\n }\n if (topP != null) {\n ollamaOptions.top_p = topP;\n }\n if (stop != null) {\n ollamaOptions.stop = stop;\n }\n if (numPredict != null) {\n ollamaOptions.num_predict = numPredict;\n }\n const hasOptions = Object.keys(ollamaOptions).length > 0;\n\n return createRunner({\n fetch: fetchFn,\n hooks,\n buildRequest: (agent, _input, messages) => ({\n url: `${baseURL}/api/chat`,\n init: {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: agent.model ?? model,\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n ],\n stream: false,\n ...(hasOptions ? { options: ollamaOptions } : {}),\n }),\n ...(timeoutMs != null\n ? { signal: AbortSignal.timeout(timeoutMs) }\n : {}),\n },\n }),\n parseResponse: async (res) => {\n let data: Record<string, unknown>;\n try {\n data = await res.json();\n } catch {\n throw new Error(\n `[Directive] Ollama returned non-JSON response. Is Ollama running at ${baseURL}? Start it with: ollama serve`,\n );\n }\n const text =\n ((data.message as Record<string, unknown>)?.content as string) ?? \"\";\n const inputTokens = (data.prompt_eval_count as number) ?? 0;\n const outputTokens = (data.eval_count as number) ?? 0;\n\n return {\n text,\n totalTokens: inputTokens + outputTokens,\n inputTokens,\n outputTokens,\n };\n },\n });\n}\n\n// ============================================================================\n// Ollama Streaming Runner\n// ============================================================================\n\n/** Options for createOllamaStreamingRunner */\nexport interface OllamaStreamingRunnerOptions {\n model?: string;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature. Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Stop sequences. The model will stop generating when it encounters one. */\n stop?: string[];\n /** Maximum number of tokens to generate. Ollama uses `num_predict`. */\n numPredict?: number;\n}\n\n/**\n * Create a StreamingCallbackRunner for local Ollama inference with\n * chunked JSON streaming. Can be used standalone or paired with `createOllamaRunner`.\n *\n * Ollama streams newline-delimited JSON objects with `{ message: { content }, done }`.\n * Token counts are included in the final chunk (`prompt_eval_count`, `eval_count`).\n *\n * Returns `tokenUsage` with input/output breakdown for resource tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createOllamaStreamingRunner({ model: 'llama3' });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createOllamaStreamingRunner(\n options: OllamaStreamingRunnerOptions = {},\n): StreamingCallbackRunner {\n const {\n model = \"llama3\",\n baseURL = \"http://localhost:11434\",\n fetch: fetchFn = globalThis.fetch,\n hooks,\n temperature,\n topP,\n stop,\n numPredict,\n } = options;\n\n validateBaseURL(baseURL);\n\n const ollamaOptions: Record<string, unknown> = {};\n if (temperature != null) {\n ollamaOptions.temperature = temperature;\n }\n if (topP != null) {\n ollamaOptions.top_p = topP;\n }\n if (stop != null) {\n ollamaOptions.stop = stop;\n }\n if (numPredict != null) {\n ollamaOptions.num_predict = numPredict;\n }\n const hasOptions = Object.keys(ollamaOptions).length > 0;\n\n return async (agent, input, callbacks) => {\n const startTime = fireBeforeCallHook(hooks, agent, input);\n\n try {\n const response = await fetchFn(`${baseURL}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: agent.model ?? model,\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n { role: \"user\", content: input },\n ],\n stream: true,\n ...(hasOptions ? { options: ollamaOptions } : {}),\n }),\n signal: callbacks.signal,\n });\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] Ollama streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n );\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error(\"[Directive] No response body from Ollama\");\n }\n\n const decoder = new TextDecoder();\n let buf = \"\";\n let fullText = \"\";\n let inputTokens = 0;\n let outputTokens = 0;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) {\n continue;\n }\n\n let chunk: Record<string, unknown>;\n try {\n chunk = JSON.parse(trimmed);\n } catch {\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV === \"development\"\n ) {\n console.warn(\n \"[Directive] Malformed streaming chunk from Ollama:\",\n trimmed,\n );\n }\n\n continue;\n }\n\n const msg = chunk.message as\n | Record<string, unknown>\n | undefined;\n const content = (msg?.content as string) ?? \"\";\n if (content) {\n fullText += content;\n callbacks.onToken?.(content);\n }\n\n if (chunk.done) {\n inputTokens =\n (chunk.prompt_eval_count as number) ?? 0;\n outputTokens = (chunk.eval_count as number) ?? 0;\n }\n }\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n\n const tokenUsage = { inputTokens, outputTokens };\n const totalTokens = inputTokens + outputTokens;\n\n callbacks.onMessage?.({ role: \"assistant\", content: fullText });\n fireAfterCallHook(hooks, agent, input, fullText, totalTokens, tokenUsage, startTime);\n\n return buildStreamingResult(input, fullText, totalTokens, tokenUsage);\n } catch (err) {\n fireErrorHook(hooks, agent, input, err, startTime);\n\n throw err;\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapters/ollama.ts"],"names":["OLLAMA_PRICING","createOllamaRunner","options","model","baseURL","fetchFn","timeoutMs","hooks","temperature","topP","stop","numPredict","validateBaseURL","ollamaOptions","hasOptions","createRunner","agent","_input","messages","m","res","data","text","inputTokens","outputTokens","createOllamaStreamingRunner","input","callbacks","startTime","fireBeforeCallHook","response","errBody","reader","decoder","buf","fullText","done","value","lines","line","trimmed","chunk","content","tokenUsage","totalTokens","fireAfterCallHook","buildStreamingResult","err","fireErrorHook"],"mappings":"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","file":"ollama.cjs","sourcesContent":["/**\n * @directive-run/ai/ollama\n *\n * Ollama adapter for Directive AI. Provides runners for local\n * Ollama inference. No API key required.\n *\n * Requires Ollama to be running locally. Start it with: `ollama serve`\n *\n * @example\n * ```typescript\n * import { createOllamaRunner } from '@directive-run/ai/ollama';\n *\n * const runner = createOllamaRunner({ model: 'llama3' });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { AdapterHooks, AgentRunner } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\nimport {\n buildStreamingResult,\n fireAfterCallHook,\n fireBeforeCallHook,\n fireErrorHook,\n} from \"./shared.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Ollama model pricing (USD per million tokens).\n *\n * Ollama runs locally — all costs are zero. This table is provided for\n * compatibility with `estimateCost()` so local models integrate seamlessly\n * into cost-tracking pipelines.\n *\n * @example\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { OLLAMA_PRICING } from '@directive-run/ai/ollama';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, OLLAMA_PRICING[\"llama3\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, OLLAMA_PRICING[\"llama3\"].output);\n * // → 0\n * ```\n */\nexport const OLLAMA_PRICING: Record<string, { input: number; output: number }> =\n {\n llama3: { input: 0, output: 0 },\n \"llama3.1\": { input: 0, output: 0 },\n \"llama3.2\": { input: 0, output: 0 },\n \"llama3.3\": { input: 0, output: 0 },\n mistral: { input: 0, output: 0 },\n mixtral: { input: 0, output: 0 },\n codellama: { input: 0, output: 0 },\n gemma2: { input: 0, output: 0 },\n phi3: { input: 0, output: 0 },\n qwen2: { input: 0, output: 0 },\n deepseek: { input: 0, output: 0 },\n \"deepseek-coder\": { input: 0, output: 0 },\n \"command-r\": { input: 0, output: 0 },\n };\n\n// ============================================================================\n// Ollama Runner\n// ============================================================================\n\n/** Options for createOllamaRunner */\nexport interface OllamaRunnerOptions {\n model?: string;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default undefined */\n timeoutMs?: number;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature. Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Stop sequences. The model will stop generating when it encounters one. */\n stop?: string[];\n /** Maximum number of tokens to generate. Ollama uses `num_predict`. */\n numPredict?: number;\n}\n\n/**\n * Create an AgentRunner for local Ollama inference.\n *\n * Ollama runs locally – no API key or cloud service needed. Default model\n * is `llama3`, default base URL is `http://localhost:11434`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking\n * (useful for monitoring local resource usage).\n *\n * @example\n * ```typescript\n * const runner = createOllamaRunner({ model: \"llama3\" });\n * const orchestrator = createAgentOrchestrator({ runner });\n * const result = await orchestrator.run(agent, input);\n * ```\n */\nexport function createOllamaRunner(\n options: OllamaRunnerOptions = {},\n): AgentRunner {\n const {\n model = \"llama3\",\n baseURL = \"http://localhost:11434\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n hooks,\n temperature,\n topP,\n stop,\n numPredict,\n } = options;\n\n validateBaseURL(baseURL);\n\n const ollamaOptions: Record<string, unknown> = {};\n if (temperature != null) {\n ollamaOptions.temperature = temperature;\n }\n if (topP != null) {\n ollamaOptions.top_p = topP;\n }\n if (stop != null) {\n ollamaOptions.stop = stop;\n }\n if (numPredict != null) {\n ollamaOptions.num_predict = numPredict;\n }\n const hasOptions = Object.keys(ollamaOptions).length > 0;\n\n return createRunner({\n fetch: fetchFn,\n hooks,\n buildRequest: (agent, _input, messages) => ({\n url: `${baseURL}/api/chat`,\n init: {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: agent.model ?? model,\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n ],\n stream: false,\n ...(hasOptions ? { options: ollamaOptions } : {}),\n }),\n ...(timeoutMs != null\n ? { signal: AbortSignal.timeout(timeoutMs) }\n : {}),\n },\n }),\n parseResponse: async (res) => {\n let data: Record<string, unknown>;\n try {\n data = await res.json();\n } catch {\n throw new Error(\n `[Directive] Ollama returned non-JSON response. Is Ollama running at ${baseURL}? Start it with: ollama serve`,\n );\n }\n const text =\n ((data.message as Record<string, unknown>)?.content as string) ?? \"\";\n const inputTokens = (data.prompt_eval_count as number) ?? 0;\n const outputTokens = (data.eval_count as number) ?? 0;\n\n return {\n text,\n totalTokens: inputTokens + outputTokens,\n inputTokens,\n outputTokens,\n };\n },\n });\n}\n\n// ============================================================================\n// Ollama Streaming Runner\n// ============================================================================\n\n/** Options for createOllamaStreamingRunner */\nexport interface OllamaStreamingRunnerOptions {\n model?: string;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature. Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Stop sequences. The model will stop generating when it encounters one. */\n stop?: string[];\n /** Maximum number of tokens to generate. Ollama uses `num_predict`. */\n numPredict?: number;\n}\n\n/**\n * Create a StreamingCallbackRunner for local Ollama inference with\n * chunked JSON streaming. Can be used standalone or paired with `createOllamaRunner`.\n *\n * Ollama streams newline-delimited JSON objects with `{ message: { content }, done }`.\n * Token counts are included in the final chunk (`prompt_eval_count`, `eval_count`).\n *\n * Returns `tokenUsage` with input/output breakdown for resource tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createOllamaStreamingRunner({ model: 'llama3' });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createOllamaStreamingRunner(\n options: OllamaStreamingRunnerOptions = {},\n): StreamingCallbackRunner {\n const {\n model = \"llama3\",\n baseURL = \"http://localhost:11434\",\n fetch: fetchFn = globalThis.fetch,\n hooks,\n temperature,\n topP,\n stop,\n numPredict,\n } = options;\n\n validateBaseURL(baseURL);\n\n const ollamaOptions: Record<string, unknown> = {};\n if (temperature != null) {\n ollamaOptions.temperature = temperature;\n }\n if (topP != null) {\n ollamaOptions.top_p = topP;\n }\n if (stop != null) {\n ollamaOptions.stop = stop;\n }\n if (numPredict != null) {\n ollamaOptions.num_predict = numPredict;\n }\n const hasOptions = Object.keys(ollamaOptions).length > 0;\n\n return async (agent, input, callbacks) => {\n const startTime = fireBeforeCallHook(hooks, agent, input);\n\n try {\n const response = await fetchFn(`${baseURL}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: agent.model ?? model,\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n { role: \"user\", content: input },\n ],\n stream: true,\n ...(hasOptions ? { options: ollamaOptions } : {}),\n }),\n signal: callbacks.signal,\n });\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] Ollama streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n );\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error(\"[Directive] No response body from Ollama\");\n }\n\n const decoder = new TextDecoder();\n let buf = \"\";\n let fullText = \"\";\n let inputTokens = 0;\n let outputTokens = 0;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) {\n continue;\n }\n\n let chunk: Record<string, unknown>;\n try {\n chunk = JSON.parse(trimmed);\n } catch {\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV === \"development\"\n ) {\n console.warn(\n \"[Directive] Malformed streaming chunk from Ollama:\",\n trimmed,\n );\n }\n\n continue;\n }\n\n const msg = chunk.message as Record<string, unknown> | undefined;\n const content = (msg?.content as string) ?? \"\";\n if (content) {\n fullText += content;\n callbacks.onToken?.(content);\n }\n\n if (chunk.done) {\n inputTokens = (chunk.prompt_eval_count as number) ?? 0;\n outputTokens = (chunk.eval_count as number) ?? 0;\n }\n }\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n\n const tokenUsage = { inputTokens, outputTokens };\n const totalTokens = inputTokens + outputTokens;\n\n callbacks.onMessage?.({ role: \"assistant\", content: fullText });\n fireAfterCallHook(\n hooks,\n agent,\n input,\n fullText,\n totalTokens,\n tokenUsage,\n startTime,\n );\n\n return buildStreamingResult(input, fullText, totalTokens, tokenUsage);\n } catch (err) {\n fireErrorHook(hooks, agent, input, err, startTime);\n\n throw err;\n }\n };\n}\n"]}
|
package/dist/ollama.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {e as e$1,f,h,g}from'./chunk-
|
|
1
|
+
import {e as e$1,f,h,g}from'./chunk-3PGRBK4E.js';import {d,e}from'./chunk-W6WZBQER.js';var J={llama3:{input:0,output:0},"llama3.1":{input:0,output:0},"llama3.2":{input:0,output:0},"llama3.3":{input:0,output:0},mistral:{input:0,output:0},mixtral:{input:0,output:0},codellama:{input:0,output:0},gemma2:{input:0,output:0},phi3:{input:0,output:0},qwen2:{input:0,output:0},deepseek:{input:0,output:0},"deepseek-coder":{input:0,output:0},"command-r":{input:0,output:0}};function B(b={}){let{model:k="llama3",baseURL:a="http://localhost:11434",fetch:O=globalThis.fetch,timeoutMs:i,hooks:f,temperature:p,topP:c,stop:m,numPredict:n}=b;d(a);let r={};p!=null&&(r.temperature=p),c!=null&&(r.top_p=c),m!=null&&(r.stop=m),n!=null&&(r.num_predict=n);let s=Object.keys(r).length>0;return e({fetch:O,hooks:f,buildRequest:(e,o,u)=>({url:`${a}/api/chat`,init:{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:e.model??k,messages:[...e.instructions?[{role:"system",content:e.instructions}]:[],...u.map(t=>({role:t.role,content:t.content}))],stream:false,...s?{options:r}:{}}),...i!=null?{signal:AbortSignal.timeout(i)}:{}}}),parseResponse:async e=>{let o;try{o=await e.json();}catch{throw new Error(`[Directive] Ollama returned non-JSON response. Is Ollama running at ${a}? Start it with: ollama serve`)}let u=o.message?.content??"",t=o.prompt_eval_count??0,l=o.eval_count??0;return {text:u,totalTokens:t+l,inputTokens:t,outputTokens:l}}})}function I(b={}){let{model:k="llama3",baseURL:a="http://localhost:11434",fetch:O=globalThis.fetch,hooks:i,temperature:f$1,topP:p,stop:c,numPredict:m}=b;d(a);let n={};f$1!=null&&(n.temperature=f$1),p!=null&&(n.top_p=p),c!=null&&(n.stop=c),m!=null&&(n.num_predict=m);let r=Object.keys(n).length>0;return async(s,e,o)=>{let u=e$1(i,s,e);try{let t=await O(`${a}/api/chat`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({model:s.model??k,messages:[...s.instructions?[{role:"system",content:s.instructions}]:[],{role:"user",content:e}],stream:!0,...r?{options:n}:{}}),signal:o.signal});if(!t.ok){let g=await t.text().catch(()=>"");throw new Error(`[Directive] Ollama streaming error ${t.status}${g?` \u2013 ${g.slice(0,200)}`:""}`)}let l=t.body?.getReader();if(!l)throw new Error("[Directive] No response body from Ollama");let D=new TextDecoder,R="",h$1="",y=0,w=0;try{for(;;){let{done:g,value:E}=await l.read();if(g)break;R+=D.decode(E,{stream:!0});let x=R.split(`
|
|
2
2
|
`);R=x.pop()??"";for(let H of x){let T=H.trim();if(!T)continue;let d;try{d=JSON.parse(T);}catch{typeof process<"u"&&process.env?.NODE_ENV==="development"&&console.warn("[Directive] Malformed streaming chunk from Ollama:",T);continue}let S=d.message?.content??"";S&&(h$1+=S,o.onToken?.(S)),d.done&&(y=d.prompt_eval_count??0,w=d.eval_count??0);}}}finally{l.cancel().catch(()=>{});}let _={inputTokens:y,outputTokens:w},P=y+w;return o.onMessage?.({role:"assistant",content:h$1}),f(i,s,e,h$1,P,_,u),h(e,h$1,P,_)}catch(t){throw g(i,s,e,t,u),t}}}export{J as OLLAMA_PRICING,B as createOllamaRunner,I as createOllamaStreamingRunner};//# sourceMappingURL=ollama.js.map
|
|
3
3
|
//# sourceMappingURL=ollama.js.map
|
package/dist/ollama.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/ollama.ts"],"names":["OLLAMA_PRICING","createOllamaRunner","options","model","baseURL","fetchFn","timeoutMs","hooks","temperature","topP","stop","numPredict","validateBaseURL","ollamaOptions","hasOptions","createRunner","agent","_input","messages","m","res","data","text","inputTokens","outputTokens","createOllamaStreamingRunner","input","callbacks","startTime","fireBeforeCallHook","response","errBody","reader","decoder","buf","fullText","done","value","lines","line","trimmed","chunk","content","tokenUsage","totalTokens","fireAfterCallHook","buildStreamingResult","err","fireErrorHook"],"mappings":"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","file":"ollama.js","sourcesContent":["/**\n * @directive-run/ai/ollama\n *\n * Ollama adapter for Directive AI. Provides runners for local\n * Ollama inference. No API key required.\n *\n * Requires Ollama to be running locally. Start it with: `ollama serve`\n *\n * @example\n * ```typescript\n * import { createOllamaRunner } from '@directive-run/ai/ollama';\n *\n * const runner = createOllamaRunner({ model: 'llama3' });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type {\n AdapterHooks,\n AgentRunner,\n} from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\nimport {\n buildStreamingResult,\n fireAfterCallHook,\n fireBeforeCallHook,\n fireErrorHook,\n} from \"./shared.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Ollama model pricing (USD per million tokens).\n *\n * Ollama runs locally — all costs are zero. This table is provided for\n * compatibility with `estimateCost()` so local models integrate seamlessly\n * into cost-tracking pipelines.\n *\n * @example\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { OLLAMA_PRICING } from '@directive-run/ai/ollama';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, OLLAMA_PRICING[\"llama3\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, OLLAMA_PRICING[\"llama3\"].output);\n * // → 0\n * ```\n */\nexport const OLLAMA_PRICING: Record<string, { input: number; output: number }> =\n {\n llama3: { input: 0, output: 0 },\n \"llama3.1\": { input: 0, output: 0 },\n \"llama3.2\": { input: 0, output: 0 },\n \"llama3.3\": { input: 0, output: 0 },\n mistral: { input: 0, output: 0 },\n mixtral: { input: 0, output: 0 },\n codellama: { input: 0, output: 0 },\n \"gemma2\": { input: 0, output: 0 },\n phi3: { input: 0, output: 0 },\n qwen2: { input: 0, output: 0 },\n deepseek: { input: 0, output: 0 },\n \"deepseek-coder\": { input: 0, output: 0 },\n \"command-r\": { input: 0, output: 0 },\n };\n\n// ============================================================================\n// Ollama Runner\n// ============================================================================\n\n/** Options for createOllamaRunner */\nexport interface OllamaRunnerOptions {\n model?: string;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default undefined */\n timeoutMs?: number;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature. Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Stop sequences. The model will stop generating when it encounters one. */\n stop?: string[];\n /** Maximum number of tokens to generate. Ollama uses `num_predict`. */\n numPredict?: number;\n}\n\n/**\n * Create an AgentRunner for local Ollama inference.\n *\n * Ollama runs locally – no API key or cloud service needed. Default model\n * is `llama3`, default base URL is `http://localhost:11434`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking\n * (useful for monitoring local resource usage).\n *\n * @example\n * ```typescript\n * const runner = createOllamaRunner({ model: \"llama3\" });\n * const orchestrator = createAgentOrchestrator({ runner });\n * const result = await orchestrator.run(agent, input);\n * ```\n */\nexport function createOllamaRunner(\n options: OllamaRunnerOptions = {},\n): AgentRunner {\n const {\n model = \"llama3\",\n baseURL = \"http://localhost:11434\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n hooks,\n temperature,\n topP,\n stop,\n numPredict,\n } = options;\n\n validateBaseURL(baseURL);\n\n const ollamaOptions: Record<string, unknown> = {};\n if (temperature != null) {\n ollamaOptions.temperature = temperature;\n }\n if (topP != null) {\n ollamaOptions.top_p = topP;\n }\n if (stop != null) {\n ollamaOptions.stop = stop;\n }\n if (numPredict != null) {\n ollamaOptions.num_predict = numPredict;\n }\n const hasOptions = Object.keys(ollamaOptions).length > 0;\n\n return createRunner({\n fetch: fetchFn,\n hooks,\n buildRequest: (agent, _input, messages) => ({\n url: `${baseURL}/api/chat`,\n init: {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: agent.model ?? model,\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n ],\n stream: false,\n ...(hasOptions ? { options: ollamaOptions } : {}),\n }),\n ...(timeoutMs != null\n ? { signal: AbortSignal.timeout(timeoutMs) }\n : {}),\n },\n }),\n parseResponse: async (res) => {\n let data: Record<string, unknown>;\n try {\n data = await res.json();\n } catch {\n throw new Error(\n `[Directive] Ollama returned non-JSON response. Is Ollama running at ${baseURL}? Start it with: ollama serve`,\n );\n }\n const text =\n ((data.message as Record<string, unknown>)?.content as string) ?? \"\";\n const inputTokens = (data.prompt_eval_count as number) ?? 0;\n const outputTokens = (data.eval_count as number) ?? 0;\n\n return {\n text,\n totalTokens: inputTokens + outputTokens,\n inputTokens,\n outputTokens,\n };\n },\n });\n}\n\n// ============================================================================\n// Ollama Streaming Runner\n// ============================================================================\n\n/** Options for createOllamaStreamingRunner */\nexport interface OllamaStreamingRunnerOptions {\n model?: string;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature. Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Stop sequences. The model will stop generating when it encounters one. */\n stop?: string[];\n /** Maximum number of tokens to generate. Ollama uses `num_predict`. */\n numPredict?: number;\n}\n\n/**\n * Create a StreamingCallbackRunner for local Ollama inference with\n * chunked JSON streaming. Can be used standalone or paired with `createOllamaRunner`.\n *\n * Ollama streams newline-delimited JSON objects with `{ message: { content }, done }`.\n * Token counts are included in the final chunk (`prompt_eval_count`, `eval_count`).\n *\n * Returns `tokenUsage` with input/output breakdown for resource tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createOllamaStreamingRunner({ model: 'llama3' });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createOllamaStreamingRunner(\n options: OllamaStreamingRunnerOptions = {},\n): StreamingCallbackRunner {\n const {\n model = \"llama3\",\n baseURL = \"http://localhost:11434\",\n fetch: fetchFn = globalThis.fetch,\n hooks,\n temperature,\n topP,\n stop,\n numPredict,\n } = options;\n\n validateBaseURL(baseURL);\n\n const ollamaOptions: Record<string, unknown> = {};\n if (temperature != null) {\n ollamaOptions.temperature = temperature;\n }\n if (topP != null) {\n ollamaOptions.top_p = topP;\n }\n if (stop != null) {\n ollamaOptions.stop = stop;\n }\n if (numPredict != null) {\n ollamaOptions.num_predict = numPredict;\n }\n const hasOptions = Object.keys(ollamaOptions).length > 0;\n\n return async (agent, input, callbacks) => {\n const startTime = fireBeforeCallHook(hooks, agent, input);\n\n try {\n const response = await fetchFn(`${baseURL}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: agent.model ?? model,\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n { role: \"user\", content: input },\n ],\n stream: true,\n ...(hasOptions ? { options: ollamaOptions } : {}),\n }),\n signal: callbacks.signal,\n });\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] Ollama streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n );\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error(\"[Directive] No response body from Ollama\");\n }\n\n const decoder = new TextDecoder();\n let buf = \"\";\n let fullText = \"\";\n let inputTokens = 0;\n let outputTokens = 0;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) {\n continue;\n }\n\n let chunk: Record<string, unknown>;\n try {\n chunk = JSON.parse(trimmed);\n } catch {\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV === \"development\"\n ) {\n console.warn(\n \"[Directive] Malformed streaming chunk from Ollama:\",\n trimmed,\n );\n }\n\n continue;\n }\n\n const msg = chunk.message as\n | Record<string, unknown>\n | undefined;\n const content = (msg?.content as string) ?? \"\";\n if (content) {\n fullText += content;\n callbacks.onToken?.(content);\n }\n\n if (chunk.done) {\n inputTokens =\n (chunk.prompt_eval_count as number) ?? 0;\n outputTokens = (chunk.eval_count as number) ?? 0;\n }\n }\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n\n const tokenUsage = { inputTokens, outputTokens };\n const totalTokens = inputTokens + outputTokens;\n\n callbacks.onMessage?.({ role: \"assistant\", content: fullText });\n fireAfterCallHook(hooks, agent, input, fullText, totalTokens, tokenUsage, startTime);\n\n return buildStreamingResult(input, fullText, totalTokens, tokenUsage);\n } catch (err) {\n fireErrorHook(hooks, agent, input, err, startTime);\n\n throw err;\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapters/ollama.ts"],"names":["OLLAMA_PRICING","createOllamaRunner","options","model","baseURL","fetchFn","timeoutMs","hooks","temperature","topP","stop","numPredict","validateBaseURL","ollamaOptions","hasOptions","createRunner","agent","_input","messages","m","res","data","text","inputTokens","outputTokens","createOllamaStreamingRunner","input","callbacks","startTime","fireBeforeCallHook","response","errBody","reader","decoder","buf","fullText","done","value","lines","line","trimmed","chunk","content","tokenUsage","totalTokens","fireAfterCallHook","buildStreamingResult","err","fireErrorHook"],"mappings":"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","file":"ollama.js","sourcesContent":["/**\n * @directive-run/ai/ollama\n *\n * Ollama adapter for Directive AI. Provides runners for local\n * Ollama inference. No API key required.\n *\n * Requires Ollama to be running locally. Start it with: `ollama serve`\n *\n * @example\n * ```typescript\n * import { createOllamaRunner } from '@directive-run/ai/ollama';\n *\n * const runner = createOllamaRunner({ model: 'llama3' });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { AdapterHooks, AgentRunner } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\nimport {\n buildStreamingResult,\n fireAfterCallHook,\n fireBeforeCallHook,\n fireErrorHook,\n} from \"./shared.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * Ollama model pricing (USD per million tokens).\n *\n * Ollama runs locally — all costs are zero. This table is provided for\n * compatibility with `estimateCost()` so local models integrate seamlessly\n * into cost-tracking pipelines.\n *\n * @example\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { OLLAMA_PRICING } from '@directive-run/ai/ollama';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, OLLAMA_PRICING[\"llama3\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, OLLAMA_PRICING[\"llama3\"].output);\n * // → 0\n * ```\n */\nexport const OLLAMA_PRICING: Record<string, { input: number; output: number }> =\n {\n llama3: { input: 0, output: 0 },\n \"llama3.1\": { input: 0, output: 0 },\n \"llama3.2\": { input: 0, output: 0 },\n \"llama3.3\": { input: 0, output: 0 },\n mistral: { input: 0, output: 0 },\n mixtral: { input: 0, output: 0 },\n codellama: { input: 0, output: 0 },\n gemma2: { input: 0, output: 0 },\n phi3: { input: 0, output: 0 },\n qwen2: { input: 0, output: 0 },\n deepseek: { input: 0, output: 0 },\n \"deepseek-coder\": { input: 0, output: 0 },\n \"command-r\": { input: 0, output: 0 },\n };\n\n// ============================================================================\n// Ollama Runner\n// ============================================================================\n\n/** Options for createOllamaRunner */\nexport interface OllamaRunnerOptions {\n model?: string;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default undefined */\n timeoutMs?: number;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature. Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Stop sequences. The model will stop generating when it encounters one. */\n stop?: string[];\n /** Maximum number of tokens to generate. Ollama uses `num_predict`. */\n numPredict?: number;\n}\n\n/**\n * Create an AgentRunner for local Ollama inference.\n *\n * Ollama runs locally – no API key or cloud service needed. Default model\n * is `llama3`, default base URL is `http://localhost:11434`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking\n * (useful for monitoring local resource usage).\n *\n * @example\n * ```typescript\n * const runner = createOllamaRunner({ model: \"llama3\" });\n * const orchestrator = createAgentOrchestrator({ runner });\n * const result = await orchestrator.run(agent, input);\n * ```\n */\nexport function createOllamaRunner(\n options: OllamaRunnerOptions = {},\n): AgentRunner {\n const {\n model = \"llama3\",\n baseURL = \"http://localhost:11434\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n hooks,\n temperature,\n topP,\n stop,\n numPredict,\n } = options;\n\n validateBaseURL(baseURL);\n\n const ollamaOptions: Record<string, unknown> = {};\n if (temperature != null) {\n ollamaOptions.temperature = temperature;\n }\n if (topP != null) {\n ollamaOptions.top_p = topP;\n }\n if (stop != null) {\n ollamaOptions.stop = stop;\n }\n if (numPredict != null) {\n ollamaOptions.num_predict = numPredict;\n }\n const hasOptions = Object.keys(ollamaOptions).length > 0;\n\n return createRunner({\n fetch: fetchFn,\n hooks,\n buildRequest: (agent, _input, messages) => ({\n url: `${baseURL}/api/chat`,\n init: {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: agent.model ?? model,\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n ],\n stream: false,\n ...(hasOptions ? { options: ollamaOptions } : {}),\n }),\n ...(timeoutMs != null\n ? { signal: AbortSignal.timeout(timeoutMs) }\n : {}),\n },\n }),\n parseResponse: async (res) => {\n let data: Record<string, unknown>;\n try {\n data = await res.json();\n } catch {\n throw new Error(\n `[Directive] Ollama returned non-JSON response. Is Ollama running at ${baseURL}? Start it with: ollama serve`,\n );\n }\n const text =\n ((data.message as Record<string, unknown>)?.content as string) ?? \"\";\n const inputTokens = (data.prompt_eval_count as number) ?? 0;\n const outputTokens = (data.eval_count as number) ?? 0;\n\n return {\n text,\n totalTokens: inputTokens + outputTokens,\n inputTokens,\n outputTokens,\n };\n },\n });\n}\n\n// ============================================================================\n// Ollama Streaming Runner\n// ============================================================================\n\n/** Options for createOllamaStreamingRunner */\nexport interface OllamaStreamingRunnerOptions {\n model?: string;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature. Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Stop sequences. The model will stop generating when it encounters one. */\n stop?: string[];\n /** Maximum number of tokens to generate. Ollama uses `num_predict`. */\n numPredict?: number;\n}\n\n/**\n * Create a StreamingCallbackRunner for local Ollama inference with\n * chunked JSON streaming. Can be used standalone or paired with `createOllamaRunner`.\n *\n * Ollama streams newline-delimited JSON objects with `{ message: { content }, done }`.\n * Token counts are included in the final chunk (`prompt_eval_count`, `eval_count`).\n *\n * Returns `tokenUsage` with input/output breakdown for resource tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createOllamaStreamingRunner({ model: 'llama3' });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createOllamaStreamingRunner(\n options: OllamaStreamingRunnerOptions = {},\n): StreamingCallbackRunner {\n const {\n model = \"llama3\",\n baseURL = \"http://localhost:11434\",\n fetch: fetchFn = globalThis.fetch,\n hooks,\n temperature,\n topP,\n stop,\n numPredict,\n } = options;\n\n validateBaseURL(baseURL);\n\n const ollamaOptions: Record<string, unknown> = {};\n if (temperature != null) {\n ollamaOptions.temperature = temperature;\n }\n if (topP != null) {\n ollamaOptions.top_p = topP;\n }\n if (stop != null) {\n ollamaOptions.stop = stop;\n }\n if (numPredict != null) {\n ollamaOptions.num_predict = numPredict;\n }\n const hasOptions = Object.keys(ollamaOptions).length > 0;\n\n return async (agent, input, callbacks) => {\n const startTime = fireBeforeCallHook(hooks, agent, input);\n\n try {\n const response = await fetchFn(`${baseURL}/api/chat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: agent.model ?? model,\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n { role: \"user\", content: input },\n ],\n stream: true,\n ...(hasOptions ? { options: ollamaOptions } : {}),\n }),\n signal: callbacks.signal,\n });\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] Ollama streaming error ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n );\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error(\"[Directive] No response body from Ollama\");\n }\n\n const decoder = new TextDecoder();\n let buf = \"\";\n let fullText = \"\";\n let inputTokens = 0;\n let outputTokens = 0;\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n if (done) {\n break;\n }\n\n buf += decoder.decode(value, { stream: true });\n const lines = buf.split(\"\\n\");\n buf = lines.pop() ?? \"\";\n\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) {\n continue;\n }\n\n let chunk: Record<string, unknown>;\n try {\n chunk = JSON.parse(trimmed);\n } catch {\n if (\n typeof process !== \"undefined\" &&\n process.env?.NODE_ENV === \"development\"\n ) {\n console.warn(\n \"[Directive] Malformed streaming chunk from Ollama:\",\n trimmed,\n );\n }\n\n continue;\n }\n\n const msg = chunk.message as Record<string, unknown> | undefined;\n const content = (msg?.content as string) ?? \"\";\n if (content) {\n fullText += content;\n callbacks.onToken?.(content);\n }\n\n if (chunk.done) {\n inputTokens = (chunk.prompt_eval_count as number) ?? 0;\n outputTokens = (chunk.eval_count as number) ?? 0;\n }\n }\n }\n } finally {\n reader.cancel().catch(() => {});\n }\n\n const tokenUsage = { inputTokens, outputTokens };\n const totalTokens = inputTokens + outputTokens;\n\n callbacks.onMessage?.({ role: \"assistant\", content: fullText });\n fireAfterCallHook(\n hooks,\n agent,\n input,\n fullText,\n totalTokens,\n tokenUsage,\n startTime,\n );\n\n return buildStreamingResult(input, fullText, totalTokens, tokenUsage);\n } catch (err) {\n fireErrorHook(hooks, agent, input, err, startTime);\n\n throw err;\n }\n };\n}\n"]}
|
package/dist/openai.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var chunkKP3G32S7_cjs=require('./chunk-KP3G32S7.cjs'),chunkW6MVJKWN_cjs=require('./chunk-W6MVJKWN.cjs');var L={"gpt-4.1":{input:2,output:8},"gpt-4.1-mini":{input:.4,output:1.6},"gpt-4.1-nano":{input:.1,output:.4},"gpt-4o":{input:2.5,output:10},"gpt-4o-mini":{input:.15,output:.6},"gpt-4-turbo":{input:10,output:30},"o4-mini":{input:1.1,output:4.4},o3:{input:10,output:40},"o3-mini":{input:1.1,output:4.4}};function B(g){let{apiKey:s,model:h="gpt-4o",maxTokens:m,baseURL:r="https://api.openai.com/v1",fetch:b=globalThis.fetch,timeoutMs:i,hooks:c,temperature:n,topP:l,stop:a,responseFormat:p}=g;chunkW6MVJKWN_cjs.d(r),chunkKP3G32S7_cjs.c(s,"createOpenAIRunner");let o=p==="json"?{type:"json_object"}:p??void 0;return chunkW6MVJKWN_cjs.e({fetch:b,hooks:c,buildRequest:(t,u,d)=>({url:`${r}/chat/completions`,init:{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({model:t.model??h,...m!=null?{max_tokens:m}:{},...n!=null?{temperature:n}:{},...l!=null?{top_p:l}:{},...a!=null?{stop:a}:{},...o!=null?{response_format:o}:{},messages:[...t.instructions?[{role:"system",content:t.instructions}]:[],...d.map(e=>({role:e.role,content:e.content}))]}),...i!=null?{signal:AbortSignal.timeout(i)}:{}}}),parseResponse:async t=>{let u=await t.json(),d=u.choices?.[0]?.message?.content??"",e=u.usage?.prompt_tokens??0,f=u.usage?.completion_tokens??0;return {text:d,totalTokens:e+f,inputTokens:e,outputTokens:f}}})}function M(g){let{apiKey:s,model:h="text-embedding-3-small",dimensions:m=1536,baseURL:r="https://api.openai.com/v1",fetch:b=globalThis.fetch,timeoutMs:i}=g;return chunkW6MVJKWN_cjs.d(r),chunkKP3G32S7_cjs.c(s,"createOpenAIEmbedder"),async c=>{let n=await b(`${r}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({model:h,input:c,dimensions:m}),signal:AbortSignal.timeout(i??3e4)});if(!n.ok){let p=await n.text().catch(()=>"");throw new Error(`[Directive] OpenAI embedding failed: ${n.status}${p?` \u2013 ${p.slice(0,200)}`:""}`)}let a=(await n.json()).data[0];if(!a)throw new Error("[Directive] OpenAI embedding response contained no data entries");return a.embedding}}function v(g){let{apiKey:s,model:h="gpt-4o",maxTokens:m,baseURL:r="https://api.openai.com/v1",fetch:b=globalThis.fetch,hooks:i,temperature:c,topP:n,stop:l,responseFormat:a}=g;chunkW6MVJKWN_cjs.d(r),chunkKP3G32S7_cjs.c(s,"createOpenAIStreamingRunner");let p=a==="json"?{type:"json_object"}:a??void 0;return async(o,t,u)=>{let d=chunkKP3G32S7_cjs.e(i,o,t);try{let e=await b(`${r}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({model:o.model??h,...m!=null?{max_tokens:m}:{},...c!=null?{temperature:c}:{},...n!=null?{top_p:n}:{},...l!=null?{stop:l}:{},...p!=null?{response_format:p}:{},messages:[...o.instructions?[{role:"system",content:o.instructions}]:[],{role:"user",content:t}],stream:!0,stream_options:{include_usage:!0}}),signal:u.signal});e.ok||await chunkKP3G32S7_cjs.a(e,"OpenAI");let f=chunkKP3G32S7_cjs.b(e),{fullText:T,inputTokens:O,outputTokens:S}=await chunkKP3G32S7_cjs.d(f,u.onToken,k=>{let y={},w=k.choices?.[0]?.delta;return w?.content&&(y.text=w.content),k.usage&&(y.inputTokens=k.usage.prompt_tokens??0,y.outputTokens=k.usage.completion_tokens??0),y},"OpenAI"),_={inputTokens:O,outputTokens:S},j=O+S;return u.onMessage?.({role:"assistant",content:T}),chunkKP3G32S7_cjs.f(i,o,t,T,j,_,d),chunkKP3G32S7_cjs.h(t,T,j,_)}catch(e){throw chunkKP3G32S7_cjs.g(i,o,t,e,d),e}}}
|
|
2
2
|
exports.OPENAI_PRICING=L;exports.createOpenAIEmbedder=M;exports.createOpenAIRunner=B;exports.createOpenAIStreamingRunner=v;//# sourceMappingURL=openai.cjs.map
|
|
3
3
|
//# sourceMappingURL=openai.cjs.map
|
package/dist/openai.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/openai.ts"],"names":["OPENAI_PRICING","createOpenAIRunner","options","apiKey","model","maxTokens","baseURL","fetchFn","timeoutMs","hooks","temperature","topP","stop","responseFormat","validateBaseURL","warnIfMissingApiKey","resolvedResponseFormat","createRunner","agent","_input","messages","m","res","data","text","inputTokens","outputTokens","createOpenAIEmbedder","dimensions","response","errBody","entry","createOpenAIStreamingRunner","input","callbacks","startTime","fireBeforeCallHook","throwStreamingHTTPError","reader","getSSEReader","fullText","parseSSEStream","event","result","delta","tokenUsage","totalTokens","fireAfterCallHook","buildStreamingResult","err","fireErrorHook"],"mappings":"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","file":"openai.cjs","sourcesContent":["/**\n * @directive-run/ai/openai\n *\n * OpenAI adapter for Directive AI. Provides runners and embedders\n * for OpenAI-compatible APIs (OpenAI, Azure, Together, etc.)\n *\n * @example\n * ```typescript\n * import { createOpenAIRunner, createOpenAIEmbedder } from '@directive-run/ai/openai';\n *\n * const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });\n * const embedder = createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { EmbedderFn, Embedding } from \"../guardrails/semantic-cache.js\";\nimport type {\n AdapterHooks,\n AgentRunner,\n} from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\nimport {\n buildStreamingResult,\n fireAfterCallHook,\n fireBeforeCallHook,\n fireErrorHook,\n getSSEReader,\n parseSSEStream,\n throwStreamingHTTPError,\n warnIfMissingApiKey,\n} from \"./shared.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * OpenAI model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { OPENAI_PRICING } from '@directive-run/ai/openai';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, OPENAI_PRICING[\"gpt-4o\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, OPENAI_PRICING[\"gpt-4o\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://openai.com/pricing\n */\nexport const OPENAI_PRICING: Record<string, { input: number; output: number }> =\n {\n \"gpt-4.1\": { input: 2, output: 8 },\n \"gpt-4.1-mini\": { input: 0.4, output: 1.6 },\n \"gpt-4.1-nano\": { input: 0.1, output: 0.4 },\n \"gpt-4o\": { input: 2.5, output: 10 },\n \"gpt-4o-mini\": { input: 0.15, output: 0.6 },\n \"gpt-4-turbo\": { input: 10, output: 30 },\n \"o4-mini\": { input: 1.1, output: 4.4 },\n \"o3\": { input: 10, output: 40 },\n \"o3-mini\": { input: 1.1, output: 4.4 },\n };\n\n// ============================================================================\n// OpenAI Runner\n// ============================================================================\n\n/** Options for createOpenAIRunner */\nexport interface OpenAIRunnerOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default undefined */\n timeoutMs?: number;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature (0–2). Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Up to 4 sequences where the API will stop generating. */\n stop?: string | string[];\n /**\n * Response format for structured output.\n * - `\"json\"` enables JSON mode (`{ type: \"json_object\" }`)\n * - Object form enables JSON Schema mode (`{ type: \"json_schema\", json_schema: ... }`)\n */\n responseFormat?: \"json\" | { type: \"json_schema\"; json_schema: unknown };\n}\n\n/**\n * Create an AgentRunner for OpenAI-compatible APIs (OpenAI, Azure, Together, etc.)\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * // OpenAI\n * const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });\n *\n * // Azure OpenAI\n * const azure = createOpenAIRunner({\n * apiKey: process.env.AZURE_KEY!,\n * baseURL: \"https://your-resource.openai.azure.com/v1\",\n * });\n *\n * // Together.ai (OpenAI-compatible)\n * const together = createOpenAIRunner({\n * apiKey: process.env.TOGETHER_KEY!,\n * baseURL: \"https://api.together.xyz/v1\",\n * });\n * ```\n */\nexport function createOpenAIRunner(options: OpenAIRunnerOptions): AgentRunner {\n const {\n apiKey,\n model = \"gpt-4o\",\n maxTokens,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n hooks,\n temperature,\n topP,\n stop,\n responseFormat,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIRunner\");\n\n const resolvedResponseFormat =\n responseFormat === \"json\"\n ? { type: \"json_object\" as const }\n : responseFormat ?? undefined;\n\n return createRunner({\n fetch: fetchFn,\n hooks,\n buildRequest: (agent, _input, messages) => ({\n url: `${baseURL}/chat/completions`,\n init: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: agent.model ?? model,\n ...(maxTokens != null ? { max_tokens: maxTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { top_p: topP } : {}),\n ...(stop != null ? { stop } : {}),\n ...(resolvedResponseFormat != null\n ? { response_format: resolvedResponseFormat }\n : {}),\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n ],\n }),\n ...(timeoutMs != null\n ? { signal: AbortSignal.timeout(timeoutMs) }\n : {}),\n },\n }),\n parseResponse: async (res) => {\n const data = await res.json();\n const text = data.choices?.[0]?.message?.content ?? \"\";\n const inputTokens = data.usage?.prompt_tokens ?? 0;\n const outputTokens = data.usage?.completion_tokens ?? 0;\n\n return {\n text,\n totalTokens: inputTokens + outputTokens,\n inputTokens,\n outputTokens,\n };\n },\n });\n}\n\n// ============================================================================\n// OpenAI Embedder\n// ============================================================================\n\n/** Options for createOpenAIEmbedder */\nexport interface OpenAIEmbedderOptions {\n apiKey: string;\n model?: string;\n dimensions?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default 30000 */\n timeoutMs?: number;\n}\n\n/**\n * Create an EmbedderFn that calls the OpenAI embeddings API.\n *\n * @example\n * ```typescript\n * const embedder = createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! });\n * const embedding = await embedder('How do constraints work?');\n * ```\n */\nexport function createOpenAIEmbedder(\n options: OpenAIEmbedderOptions,\n): EmbedderFn {\n const {\n apiKey,\n model = \"text-embedding-3-small\",\n dimensions = 1536,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIEmbedder\");\n\n return async (text: string): Promise<Embedding> => {\n const response = await fetchFn(`${baseURL}/embeddings`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ model, input: text, dimensions }),\n signal: AbortSignal.timeout(timeoutMs ?? 30_000),\n });\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] OpenAI embedding failed: ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n );\n }\n\n const data = (await response.json()) as {\n data: Array<{ embedding: number[] }>;\n };\n\n const entry = data.data[0];\n if (!entry) {\n throw new Error(\n \"[Directive] OpenAI embedding response contained no data entries\",\n );\n }\n\n return entry.embedding;\n };\n}\n\n// ============================================================================\n// OpenAI Streaming Runner\n// ============================================================================\n\n/** Options for createOpenAIStreamingRunner */\nexport interface OpenAIStreamingRunnerOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature (0–2). Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Up to 4 sequences where the API will stop generating. */\n stop?: string | string[];\n /**\n * Response format for structured output.\n * - `\"json\"` enables JSON mode (`{ type: \"json_object\" }`)\n * - Object form enables JSON Schema mode (`{ type: \"json_schema\", json_schema: ... }`)\n */\n responseFormat?: \"json\" | { type: \"json_schema\"; json_schema: unknown };\n}\n\n/**\n * Create a StreamingCallbackRunner for OpenAI-compatible chat completions\n * with server-sent events. Can be used standalone or paired with `createOpenAIRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createOpenAIStreamingRunner({\n * apiKey: process.env.OPENAI_API_KEY!,\n * });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createOpenAIStreamingRunner(\n options: OpenAIStreamingRunnerOptions,\n): StreamingCallbackRunner {\n const {\n apiKey,\n model = \"gpt-4o\",\n maxTokens,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n hooks,\n temperature,\n topP,\n stop,\n responseFormat,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIStreamingRunner\");\n\n const resolvedResponseFormat =\n responseFormat === \"json\"\n ? { type: \"json_object\" as const }\n : responseFormat ?? undefined;\n\n return async (agent, input, callbacks) => {\n const startTime = fireBeforeCallHook(hooks, agent, input);\n\n try {\n const response = await fetchFn(`${baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: agent.model ?? model,\n ...(maxTokens != null ? { max_tokens: maxTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { top_p: topP } : {}),\n ...(stop != null ? { stop } : {}),\n ...(resolvedResponseFormat != null\n ? { response_format: resolvedResponseFormat }\n : {}),\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n { role: \"user\", content: input },\n ],\n stream: true,\n stream_options: { include_usage: true },\n }),\n signal: callbacks.signal,\n });\n\n if (!response.ok) {\n await throwStreamingHTTPError(response, \"OpenAI\");\n }\n\n const reader = getSSEReader(response);\n\n const { fullText, inputTokens, outputTokens } = await parseSSEStream(\n reader,\n callbacks.onToken,\n (event) => {\n const result: { text?: string; inputTokens?: number; outputTokens?: number } = {};\n\n const delta = (event.choices as Array<Record<string, unknown>>)?.[0]\n ?.delta as Record<string, unknown> | undefined;\n if (delta?.content) {\n result.text = delta.content as string;\n }\n\n if (event.usage) {\n result.inputTokens = (event.usage as Record<string, unknown>).prompt_tokens as number ?? 0;\n result.outputTokens = (event.usage as Record<string, unknown>).completion_tokens as number ?? 0;\n }\n\n return result;\n },\n \"OpenAI\",\n );\n\n const tokenUsage = { inputTokens, outputTokens };\n const totalTokens = inputTokens + outputTokens;\n\n callbacks.onMessage?.({ role: \"assistant\", content: fullText });\n fireAfterCallHook(hooks, agent, input, fullText, totalTokens, tokenUsage, startTime);\n\n return buildStreamingResult(input, fullText, totalTokens, tokenUsage);\n } catch (err) {\n fireErrorHook(hooks, agent, input, err, startTime);\n\n throw err;\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapters/openai.ts"],"names":["OPENAI_PRICING","createOpenAIRunner","options","apiKey","model","maxTokens","baseURL","fetchFn","timeoutMs","hooks","temperature","topP","stop","responseFormat","validateBaseURL","warnIfMissingApiKey","resolvedResponseFormat","createRunner","agent","_input","messages","m","res","data","text","inputTokens","outputTokens","createOpenAIEmbedder","dimensions","response","errBody","entry","createOpenAIStreamingRunner","input","callbacks","startTime","fireBeforeCallHook","throwStreamingHTTPError","reader","getSSEReader","fullText","parseSSEStream","event","result","delta","tokenUsage","totalTokens","fireAfterCallHook","buildStreamingResult","err","fireErrorHook"],"mappings":"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","file":"openai.cjs","sourcesContent":["/**\n * @directive-run/ai/openai\n *\n * OpenAI adapter for Directive AI. Provides runners and embedders\n * for OpenAI-compatible APIs (OpenAI, Azure, Together, etc.)\n *\n * @example\n * ```typescript\n * import { createOpenAIRunner, createOpenAIEmbedder } from '@directive-run/ai/openai';\n *\n * const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });\n * const embedder = createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { EmbedderFn, Embedding } from \"../guardrails/semantic-cache.js\";\nimport type { AdapterHooks, AgentRunner } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\nimport {\n buildStreamingResult,\n fireAfterCallHook,\n fireBeforeCallHook,\n fireErrorHook,\n getSSEReader,\n parseSSEStream,\n throwStreamingHTTPError,\n warnIfMissingApiKey,\n} from \"./shared.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * OpenAI model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { OPENAI_PRICING } from '@directive-run/ai/openai';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, OPENAI_PRICING[\"gpt-4o\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, OPENAI_PRICING[\"gpt-4o\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://openai.com/pricing\n */\nexport const OPENAI_PRICING: Record<string, { input: number; output: number }> =\n {\n \"gpt-4.1\": { input: 2, output: 8 },\n \"gpt-4.1-mini\": { input: 0.4, output: 1.6 },\n \"gpt-4.1-nano\": { input: 0.1, output: 0.4 },\n \"gpt-4o\": { input: 2.5, output: 10 },\n \"gpt-4o-mini\": { input: 0.15, output: 0.6 },\n \"gpt-4-turbo\": { input: 10, output: 30 },\n \"o4-mini\": { input: 1.1, output: 4.4 },\n o3: { input: 10, output: 40 },\n \"o3-mini\": { input: 1.1, output: 4.4 },\n };\n\n// ============================================================================\n// OpenAI Runner\n// ============================================================================\n\n/** Options for createOpenAIRunner */\nexport interface OpenAIRunnerOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default undefined */\n timeoutMs?: number;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature (0–2). Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Up to 4 sequences where the API will stop generating. */\n stop?: string | string[];\n /**\n * Response format for structured output.\n * - `\"json\"` enables JSON mode (`{ type: \"json_object\" }`)\n * - Object form enables JSON Schema mode (`{ type: \"json_schema\", json_schema: ... }`)\n */\n responseFormat?: \"json\" | { type: \"json_schema\"; json_schema: unknown };\n}\n\n/**\n * Create an AgentRunner for OpenAI-compatible APIs (OpenAI, Azure, Together, etc.)\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * // OpenAI\n * const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });\n *\n * // Azure OpenAI\n * const azure = createOpenAIRunner({\n * apiKey: process.env.AZURE_KEY!,\n * baseURL: \"https://your-resource.openai.azure.com/v1\",\n * });\n *\n * // Together.ai (OpenAI-compatible)\n * const together = createOpenAIRunner({\n * apiKey: process.env.TOGETHER_KEY!,\n * baseURL: \"https://api.together.xyz/v1\",\n * });\n * ```\n */\nexport function createOpenAIRunner(options: OpenAIRunnerOptions): AgentRunner {\n const {\n apiKey,\n model = \"gpt-4o\",\n maxTokens,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n hooks,\n temperature,\n topP,\n stop,\n responseFormat,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIRunner\");\n\n const resolvedResponseFormat =\n responseFormat === \"json\"\n ? { type: \"json_object\" as const }\n : (responseFormat ?? undefined);\n\n return createRunner({\n fetch: fetchFn,\n hooks,\n buildRequest: (agent, _input, messages) => ({\n url: `${baseURL}/chat/completions`,\n init: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: agent.model ?? model,\n ...(maxTokens != null ? { max_tokens: maxTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { top_p: topP } : {}),\n ...(stop != null ? { stop } : {}),\n ...(resolvedResponseFormat != null\n ? { response_format: resolvedResponseFormat }\n : {}),\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n ],\n }),\n ...(timeoutMs != null\n ? { signal: AbortSignal.timeout(timeoutMs) }\n : {}),\n },\n }),\n parseResponse: async (res) => {\n const data = await res.json();\n const text = data.choices?.[0]?.message?.content ?? \"\";\n const inputTokens = data.usage?.prompt_tokens ?? 0;\n const outputTokens = data.usage?.completion_tokens ?? 0;\n\n return {\n text,\n totalTokens: inputTokens + outputTokens,\n inputTokens,\n outputTokens,\n };\n },\n });\n}\n\n// ============================================================================\n// OpenAI Embedder\n// ============================================================================\n\n/** Options for createOpenAIEmbedder */\nexport interface OpenAIEmbedderOptions {\n apiKey: string;\n model?: string;\n dimensions?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default 30000 */\n timeoutMs?: number;\n}\n\n/**\n * Create an EmbedderFn that calls the OpenAI embeddings API.\n *\n * @example\n * ```typescript\n * const embedder = createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! });\n * const embedding = await embedder('How do constraints work?');\n * ```\n */\nexport function createOpenAIEmbedder(\n options: OpenAIEmbedderOptions,\n): EmbedderFn {\n const {\n apiKey,\n model = \"text-embedding-3-small\",\n dimensions = 1536,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIEmbedder\");\n\n return async (text: string): Promise<Embedding> => {\n const response = await fetchFn(`${baseURL}/embeddings`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ model, input: text, dimensions }),\n signal: AbortSignal.timeout(timeoutMs ?? 30_000),\n });\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] OpenAI embedding failed: ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n );\n }\n\n const data = (await response.json()) as {\n data: Array<{ embedding: number[] }>;\n };\n\n const entry = data.data[0];\n if (!entry) {\n throw new Error(\n \"[Directive] OpenAI embedding response contained no data entries\",\n );\n }\n\n return entry.embedding;\n };\n}\n\n// ============================================================================\n// OpenAI Streaming Runner\n// ============================================================================\n\n/** Options for createOpenAIStreamingRunner */\nexport interface OpenAIStreamingRunnerOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature (0–2). Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Up to 4 sequences where the API will stop generating. */\n stop?: string | string[];\n /**\n * Response format for structured output.\n * - `\"json\"` enables JSON mode (`{ type: \"json_object\" }`)\n * - Object form enables JSON Schema mode (`{ type: \"json_schema\", json_schema: ... }`)\n */\n responseFormat?: \"json\" | { type: \"json_schema\"; json_schema: unknown };\n}\n\n/**\n * Create a StreamingCallbackRunner for OpenAI-compatible chat completions\n * with server-sent events. Can be used standalone or paired with `createOpenAIRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createOpenAIStreamingRunner({\n * apiKey: process.env.OPENAI_API_KEY!,\n * });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createOpenAIStreamingRunner(\n options: OpenAIStreamingRunnerOptions,\n): StreamingCallbackRunner {\n const {\n apiKey,\n model = \"gpt-4o\",\n maxTokens,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n hooks,\n temperature,\n topP,\n stop,\n responseFormat,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIStreamingRunner\");\n\n const resolvedResponseFormat =\n responseFormat === \"json\"\n ? { type: \"json_object\" as const }\n : (responseFormat ?? undefined);\n\n return async (agent, input, callbacks) => {\n const startTime = fireBeforeCallHook(hooks, agent, input);\n\n try {\n const response = await fetchFn(`${baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: agent.model ?? model,\n ...(maxTokens != null ? { max_tokens: maxTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { top_p: topP } : {}),\n ...(stop != null ? { stop } : {}),\n ...(resolvedResponseFormat != null\n ? { response_format: resolvedResponseFormat }\n : {}),\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n { role: \"user\", content: input },\n ],\n stream: true,\n stream_options: { include_usage: true },\n }),\n signal: callbacks.signal,\n });\n\n if (!response.ok) {\n await throwStreamingHTTPError(response, \"OpenAI\");\n }\n\n const reader = getSSEReader(response);\n\n const { fullText, inputTokens, outputTokens } = await parseSSEStream(\n reader,\n callbacks.onToken,\n (event) => {\n const result: {\n text?: string;\n inputTokens?: number;\n outputTokens?: number;\n } = {};\n\n const delta = (event.choices as Array<Record<string, unknown>>)?.[0]\n ?.delta as Record<string, unknown> | undefined;\n if (delta?.content) {\n result.text = delta.content as string;\n }\n\n if (event.usage) {\n result.inputTokens =\n ((event.usage as Record<string, unknown>)\n .prompt_tokens as number) ?? 0;\n result.outputTokens =\n ((event.usage as Record<string, unknown>)\n .completion_tokens as number) ?? 0;\n }\n\n return result;\n },\n \"OpenAI\",\n );\n\n const tokenUsage = { inputTokens, outputTokens };\n const totalTokens = inputTokens + outputTokens;\n\n callbacks.onMessage?.({ role: \"assistant\", content: fullText });\n fireAfterCallHook(\n hooks,\n agent,\n input,\n fullText,\n totalTokens,\n tokenUsage,\n startTime,\n );\n\n return buildStreamingResult(input, fullText, totalTokens, tokenUsage);\n } catch (err) {\n fireErrorHook(hooks, agent, input, err, startTime);\n\n throw err;\n }\n };\n}\n"]}
|
package/dist/openai.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {c,e as e$1,a,b,d as d$1,f,h,g}from'./chunk-
|
|
1
|
+
import {c,e as e$1,a,b,d as d$1,f,h,g}from'./chunk-3PGRBK4E.js';import {d,e}from'./chunk-W6WZBQER.js';var L={"gpt-4.1":{input:2,output:8},"gpt-4.1-mini":{input:.4,output:1.6},"gpt-4.1-nano":{input:.1,output:.4},"gpt-4o":{input:2.5,output:10},"gpt-4o-mini":{input:.15,output:.6},"gpt-4-turbo":{input:10,output:30},"o4-mini":{input:1.1,output:4.4},o3:{input:10,output:40},"o3-mini":{input:1.1,output:4.4}};function B(g){let{apiKey:s,model:h="gpt-4o",maxTokens:m,baseURL:r="https://api.openai.com/v1",fetch:b=globalThis.fetch,timeoutMs:i,hooks:c$1,temperature:n,topP:l,stop:a,responseFormat:p}=g;d(r),c(s,"createOpenAIRunner");let o=p==="json"?{type:"json_object"}:p??void 0;return e({fetch:b,hooks:c$1,buildRequest:(t,u,d)=>({url:`${r}/chat/completions`,init:{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({model:t.model??h,...m!=null?{max_tokens:m}:{},...n!=null?{temperature:n}:{},...l!=null?{top_p:l}:{},...a!=null?{stop:a}:{},...o!=null?{response_format:o}:{},messages:[...t.instructions?[{role:"system",content:t.instructions}]:[],...d.map(e=>({role:e.role,content:e.content}))]}),...i!=null?{signal:AbortSignal.timeout(i)}:{}}}),parseResponse:async t=>{let u=await t.json(),d=u.choices?.[0]?.message?.content??"",e=u.usage?.prompt_tokens??0,f=u.usage?.completion_tokens??0;return {text:d,totalTokens:e+f,inputTokens:e,outputTokens:f}}})}function M(g){let{apiKey:s,model:h="text-embedding-3-small",dimensions:m=1536,baseURL:r="https://api.openai.com/v1",fetch:b=globalThis.fetch,timeoutMs:i}=g;return d(r),c(s,"createOpenAIEmbedder"),async c=>{let n=await b(`${r}/embeddings`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({model:h,input:c,dimensions:m}),signal:AbortSignal.timeout(i??3e4)});if(!n.ok){let p=await n.text().catch(()=>"");throw new Error(`[Directive] OpenAI embedding failed: ${n.status}${p?` \u2013 ${p.slice(0,200)}`:""}`)}let a=(await n.json()).data[0];if(!a)throw new Error("[Directive] OpenAI embedding response contained no data entries");return a.embedding}}function v(g$1){let{apiKey:s,model:h$1="gpt-4o",maxTokens:m,baseURL:r="https://api.openai.com/v1",fetch:b$1=globalThis.fetch,hooks:i,temperature:c$1,topP:n,stop:l,responseFormat:a$1}=g$1;d(r),c(s,"createOpenAIStreamingRunner");let p=a$1==="json"?{type:"json_object"}:a$1??void 0;return async(o,t,u)=>{let d=e$1(i,o,t);try{let e=await b$1(`${r}/chat/completions`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${s}`},body:JSON.stringify({model:o.model??h$1,...m!=null?{max_tokens:m}:{},...c$1!=null?{temperature:c$1}:{},...n!=null?{top_p:n}:{},...l!=null?{stop:l}:{},...p!=null?{response_format:p}:{},messages:[...o.instructions?[{role:"system",content:o.instructions}]:[],{role:"user",content:t}],stream:!0,stream_options:{include_usage:!0}}),signal:u.signal});e.ok||await a(e,"OpenAI");let f$1=b(e),{fullText:T,inputTokens:O,outputTokens:S}=await d$1(f$1,u.onToken,k=>{let y={},w=k.choices?.[0]?.delta;return w?.content&&(y.text=w.content),k.usage&&(y.inputTokens=k.usage.prompt_tokens??0,y.outputTokens=k.usage.completion_tokens??0),y},"OpenAI"),_={inputTokens:O,outputTokens:S},j=O+S;return u.onMessage?.({role:"assistant",content:T}),f(i,o,t,T,j,_,d),h(t,T,j,_)}catch(e){throw g(i,o,t,e,d),e}}}
|
|
2
2
|
export{L as OPENAI_PRICING,M as createOpenAIEmbedder,B as createOpenAIRunner,v as createOpenAIStreamingRunner};//# sourceMappingURL=openai.js.map
|
|
3
3
|
//# sourceMappingURL=openai.js.map
|
package/dist/openai.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/adapters/openai.ts"],"names":["OPENAI_PRICING","createOpenAIRunner","options","apiKey","model","maxTokens","baseURL","fetchFn","timeoutMs","hooks","temperature","topP","stop","responseFormat","validateBaseURL","warnIfMissingApiKey","resolvedResponseFormat","createRunner","agent","_input","messages","m","res","data","text","inputTokens","outputTokens","createOpenAIEmbedder","dimensions","response","errBody","entry","createOpenAIStreamingRunner","input","callbacks","startTime","fireBeforeCallHook","throwStreamingHTTPError","reader","getSSEReader","fullText","parseSSEStream","event","result","delta","tokenUsage","totalTokens","fireAfterCallHook","buildStreamingResult","err","fireErrorHook"],"mappings":"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","file":"openai.js","sourcesContent":["/**\n * @directive-run/ai/openai\n *\n * OpenAI adapter for Directive AI. Provides runners and embedders\n * for OpenAI-compatible APIs (OpenAI, Azure, Together, etc.)\n *\n * @example\n * ```typescript\n * import { createOpenAIRunner, createOpenAIEmbedder } from '@directive-run/ai/openai';\n *\n * const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });\n * const embedder = createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { EmbedderFn, Embedding } from \"../guardrails/semantic-cache.js\";\nimport type {\n AdapterHooks,\n AgentRunner,\n} from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\nimport {\n buildStreamingResult,\n fireAfterCallHook,\n fireBeforeCallHook,\n fireErrorHook,\n getSSEReader,\n parseSSEStream,\n throwStreamingHTTPError,\n warnIfMissingApiKey,\n} from \"./shared.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * OpenAI model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { OPENAI_PRICING } from '@directive-run/ai/openai';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, OPENAI_PRICING[\"gpt-4o\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, OPENAI_PRICING[\"gpt-4o\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://openai.com/pricing\n */\nexport const OPENAI_PRICING: Record<string, { input: number; output: number }> =\n {\n \"gpt-4.1\": { input: 2, output: 8 },\n \"gpt-4.1-mini\": { input: 0.4, output: 1.6 },\n \"gpt-4.1-nano\": { input: 0.1, output: 0.4 },\n \"gpt-4o\": { input: 2.5, output: 10 },\n \"gpt-4o-mini\": { input: 0.15, output: 0.6 },\n \"gpt-4-turbo\": { input: 10, output: 30 },\n \"o4-mini\": { input: 1.1, output: 4.4 },\n \"o3\": { input: 10, output: 40 },\n \"o3-mini\": { input: 1.1, output: 4.4 },\n };\n\n// ============================================================================\n// OpenAI Runner\n// ============================================================================\n\n/** Options for createOpenAIRunner */\nexport interface OpenAIRunnerOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default undefined */\n timeoutMs?: number;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature (0–2). Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Up to 4 sequences where the API will stop generating. */\n stop?: string | string[];\n /**\n * Response format for structured output.\n * - `\"json\"` enables JSON mode (`{ type: \"json_object\" }`)\n * - Object form enables JSON Schema mode (`{ type: \"json_schema\", json_schema: ... }`)\n */\n responseFormat?: \"json\" | { type: \"json_schema\"; json_schema: unknown };\n}\n\n/**\n * Create an AgentRunner for OpenAI-compatible APIs (OpenAI, Azure, Together, etc.)\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * // OpenAI\n * const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });\n *\n * // Azure OpenAI\n * const azure = createOpenAIRunner({\n * apiKey: process.env.AZURE_KEY!,\n * baseURL: \"https://your-resource.openai.azure.com/v1\",\n * });\n *\n * // Together.ai (OpenAI-compatible)\n * const together = createOpenAIRunner({\n * apiKey: process.env.TOGETHER_KEY!,\n * baseURL: \"https://api.together.xyz/v1\",\n * });\n * ```\n */\nexport function createOpenAIRunner(options: OpenAIRunnerOptions): AgentRunner {\n const {\n apiKey,\n model = \"gpt-4o\",\n maxTokens,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n hooks,\n temperature,\n topP,\n stop,\n responseFormat,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIRunner\");\n\n const resolvedResponseFormat =\n responseFormat === \"json\"\n ? { type: \"json_object\" as const }\n : responseFormat ?? undefined;\n\n return createRunner({\n fetch: fetchFn,\n hooks,\n buildRequest: (agent, _input, messages) => ({\n url: `${baseURL}/chat/completions`,\n init: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: agent.model ?? model,\n ...(maxTokens != null ? { max_tokens: maxTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { top_p: topP } : {}),\n ...(stop != null ? { stop } : {}),\n ...(resolvedResponseFormat != null\n ? { response_format: resolvedResponseFormat }\n : {}),\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n ],\n }),\n ...(timeoutMs != null\n ? { signal: AbortSignal.timeout(timeoutMs) }\n : {}),\n },\n }),\n parseResponse: async (res) => {\n const data = await res.json();\n const text = data.choices?.[0]?.message?.content ?? \"\";\n const inputTokens = data.usage?.prompt_tokens ?? 0;\n const outputTokens = data.usage?.completion_tokens ?? 0;\n\n return {\n text,\n totalTokens: inputTokens + outputTokens,\n inputTokens,\n outputTokens,\n };\n },\n });\n}\n\n// ============================================================================\n// OpenAI Embedder\n// ============================================================================\n\n/** Options for createOpenAIEmbedder */\nexport interface OpenAIEmbedderOptions {\n apiKey: string;\n model?: string;\n dimensions?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default 30000 */\n timeoutMs?: number;\n}\n\n/**\n * Create an EmbedderFn that calls the OpenAI embeddings API.\n *\n * @example\n * ```typescript\n * const embedder = createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! });\n * const embedding = await embedder('How do constraints work?');\n * ```\n */\nexport function createOpenAIEmbedder(\n options: OpenAIEmbedderOptions,\n): EmbedderFn {\n const {\n apiKey,\n model = \"text-embedding-3-small\",\n dimensions = 1536,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIEmbedder\");\n\n return async (text: string): Promise<Embedding> => {\n const response = await fetchFn(`${baseURL}/embeddings`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ model, input: text, dimensions }),\n signal: AbortSignal.timeout(timeoutMs ?? 30_000),\n });\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] OpenAI embedding failed: ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n );\n }\n\n const data = (await response.json()) as {\n data: Array<{ embedding: number[] }>;\n };\n\n const entry = data.data[0];\n if (!entry) {\n throw new Error(\n \"[Directive] OpenAI embedding response contained no data entries\",\n );\n }\n\n return entry.embedding;\n };\n}\n\n// ============================================================================\n// OpenAI Streaming Runner\n// ============================================================================\n\n/** Options for createOpenAIStreamingRunner */\nexport interface OpenAIStreamingRunnerOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature (0–2). Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Up to 4 sequences where the API will stop generating. */\n stop?: string | string[];\n /**\n * Response format for structured output.\n * - `\"json\"` enables JSON mode (`{ type: \"json_object\" }`)\n * - Object form enables JSON Schema mode (`{ type: \"json_schema\", json_schema: ... }`)\n */\n responseFormat?: \"json\" | { type: \"json_schema\"; json_schema: unknown };\n}\n\n/**\n * Create a StreamingCallbackRunner for OpenAI-compatible chat completions\n * with server-sent events. Can be used standalone or paired with `createOpenAIRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createOpenAIStreamingRunner({\n * apiKey: process.env.OPENAI_API_KEY!,\n * });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createOpenAIStreamingRunner(\n options: OpenAIStreamingRunnerOptions,\n): StreamingCallbackRunner {\n const {\n apiKey,\n model = \"gpt-4o\",\n maxTokens,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n hooks,\n temperature,\n topP,\n stop,\n responseFormat,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIStreamingRunner\");\n\n const resolvedResponseFormat =\n responseFormat === \"json\"\n ? { type: \"json_object\" as const }\n : responseFormat ?? undefined;\n\n return async (agent, input, callbacks) => {\n const startTime = fireBeforeCallHook(hooks, agent, input);\n\n try {\n const response = await fetchFn(`${baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: agent.model ?? model,\n ...(maxTokens != null ? { max_tokens: maxTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { top_p: topP } : {}),\n ...(stop != null ? { stop } : {}),\n ...(resolvedResponseFormat != null\n ? { response_format: resolvedResponseFormat }\n : {}),\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n { role: \"user\", content: input },\n ],\n stream: true,\n stream_options: { include_usage: true },\n }),\n signal: callbacks.signal,\n });\n\n if (!response.ok) {\n await throwStreamingHTTPError(response, \"OpenAI\");\n }\n\n const reader = getSSEReader(response);\n\n const { fullText, inputTokens, outputTokens } = await parseSSEStream(\n reader,\n callbacks.onToken,\n (event) => {\n const result: { text?: string; inputTokens?: number; outputTokens?: number } = {};\n\n const delta = (event.choices as Array<Record<string, unknown>>)?.[0]\n ?.delta as Record<string, unknown> | undefined;\n if (delta?.content) {\n result.text = delta.content as string;\n }\n\n if (event.usage) {\n result.inputTokens = (event.usage as Record<string, unknown>).prompt_tokens as number ?? 0;\n result.outputTokens = (event.usage as Record<string, unknown>).completion_tokens as number ?? 0;\n }\n\n return result;\n },\n \"OpenAI\",\n );\n\n const tokenUsage = { inputTokens, outputTokens };\n const totalTokens = inputTokens + outputTokens;\n\n callbacks.onMessage?.({ role: \"assistant\", content: fullText });\n fireAfterCallHook(hooks, agent, input, fullText, totalTokens, tokenUsage, startTime);\n\n return buildStreamingResult(input, fullText, totalTokens, tokenUsage);\n } catch (err) {\n fireErrorHook(hooks, agent, input, err, startTime);\n\n throw err;\n }\n };\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/adapters/openai.ts"],"names":["OPENAI_PRICING","createOpenAIRunner","options","apiKey","model","maxTokens","baseURL","fetchFn","timeoutMs","hooks","temperature","topP","stop","responseFormat","validateBaseURL","warnIfMissingApiKey","resolvedResponseFormat","createRunner","agent","_input","messages","m","res","data","text","inputTokens","outputTokens","createOpenAIEmbedder","dimensions","response","errBody","entry","createOpenAIStreamingRunner","input","callbacks","startTime","fireBeforeCallHook","throwStreamingHTTPError","reader","getSSEReader","fullText","parseSSEStream","event","result","delta","tokenUsage","totalTokens","fireAfterCallHook","buildStreamingResult","err","fireErrorHook"],"mappings":"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","file":"openai.js","sourcesContent":["/**\n * @directive-run/ai/openai\n *\n * OpenAI adapter for Directive AI. Provides runners and embedders\n * for OpenAI-compatible APIs (OpenAI, Azure, Together, etc.)\n *\n * @example\n * ```typescript\n * import { createOpenAIRunner, createOpenAIEmbedder } from '@directive-run/ai/openai';\n *\n * const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });\n * const embedder = createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! });\n * ```\n */\n\nimport { createRunner, validateBaseURL } from \"../agent-utils.js\";\nimport type { EmbedderFn, Embedding } from \"../guardrails/semantic-cache.js\";\nimport type { AdapterHooks, AgentRunner } from \"../types.js\";\nimport type { StreamingCallbackRunner } from \"../types.js\";\nimport {\n buildStreamingResult,\n fireAfterCallHook,\n fireBeforeCallHook,\n fireErrorHook,\n getSSEReader,\n parseSSEStream,\n throwStreamingHTTPError,\n warnIfMissingApiKey,\n} from \"./shared.js\";\n\n// ============================================================================\n// Pricing Constants\n// ============================================================================\n\n/**\n * OpenAI model pricing (USD per million tokens).\n *\n * Use with `estimateCost()` for per-call cost tracking:\n * ```typescript\n * import { estimateCost } from '@directive-run/ai';\n * import { OPENAI_PRICING } from '@directive-run/ai/openai';\n *\n * const cost =\n * estimateCost(result.tokenUsage!.inputTokens, OPENAI_PRICING[\"gpt-4o\"].input) +\n * estimateCost(result.tokenUsage!.outputTokens, OPENAI_PRICING[\"gpt-4o\"].output);\n * ```\n *\n * **Note:** Pricing changes over time. These values are provided as a convenience\n * and may not reflect the latest rates. Always verify at https://openai.com/pricing\n */\nexport const OPENAI_PRICING: Record<string, { input: number; output: number }> =\n {\n \"gpt-4.1\": { input: 2, output: 8 },\n \"gpt-4.1-mini\": { input: 0.4, output: 1.6 },\n \"gpt-4.1-nano\": { input: 0.1, output: 0.4 },\n \"gpt-4o\": { input: 2.5, output: 10 },\n \"gpt-4o-mini\": { input: 0.15, output: 0.6 },\n \"gpt-4-turbo\": { input: 10, output: 30 },\n \"o4-mini\": { input: 1.1, output: 4.4 },\n o3: { input: 10, output: 40 },\n \"o3-mini\": { input: 1.1, output: 4.4 },\n };\n\n// ============================================================================\n// OpenAI Runner\n// ============================================================================\n\n/** Options for createOpenAIRunner */\nexport interface OpenAIRunnerOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default undefined */\n timeoutMs?: number;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature (0–2). Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Up to 4 sequences where the API will stop generating. */\n stop?: string | string[];\n /**\n * Response format for structured output.\n * - `\"json\"` enables JSON mode (`{ type: \"json_object\" }`)\n * - Object form enables JSON Schema mode (`{ type: \"json_schema\", json_schema: ... }`)\n */\n responseFormat?: \"json\" | { type: \"json_schema\"; json_schema: unknown };\n}\n\n/**\n * Create an AgentRunner for OpenAI-compatible APIs (OpenAI, Azure, Together, etc.)\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * // OpenAI\n * const runner = createOpenAIRunner({ apiKey: process.env.OPENAI_API_KEY! });\n *\n * // Azure OpenAI\n * const azure = createOpenAIRunner({\n * apiKey: process.env.AZURE_KEY!,\n * baseURL: \"https://your-resource.openai.azure.com/v1\",\n * });\n *\n * // Together.ai (OpenAI-compatible)\n * const together = createOpenAIRunner({\n * apiKey: process.env.TOGETHER_KEY!,\n * baseURL: \"https://api.together.xyz/v1\",\n * });\n * ```\n */\nexport function createOpenAIRunner(options: OpenAIRunnerOptions): AgentRunner {\n const {\n apiKey,\n model = \"gpt-4o\",\n maxTokens,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n hooks,\n temperature,\n topP,\n stop,\n responseFormat,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIRunner\");\n\n const resolvedResponseFormat =\n responseFormat === \"json\"\n ? { type: \"json_object\" as const }\n : (responseFormat ?? undefined);\n\n return createRunner({\n fetch: fetchFn,\n hooks,\n buildRequest: (agent, _input, messages) => ({\n url: `${baseURL}/chat/completions`,\n init: {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: agent.model ?? model,\n ...(maxTokens != null ? { max_tokens: maxTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { top_p: topP } : {}),\n ...(stop != null ? { stop } : {}),\n ...(resolvedResponseFormat != null\n ? { response_format: resolvedResponseFormat }\n : {}),\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n ...messages.map((m) => ({ role: m.role, content: m.content })),\n ],\n }),\n ...(timeoutMs != null\n ? { signal: AbortSignal.timeout(timeoutMs) }\n : {}),\n },\n }),\n parseResponse: async (res) => {\n const data = await res.json();\n const text = data.choices?.[0]?.message?.content ?? \"\";\n const inputTokens = data.usage?.prompt_tokens ?? 0;\n const outputTokens = data.usage?.completion_tokens ?? 0;\n\n return {\n text,\n totalTokens: inputTokens + outputTokens,\n inputTokens,\n outputTokens,\n };\n },\n });\n}\n\n// ============================================================================\n// OpenAI Embedder\n// ============================================================================\n\n/** Options for createOpenAIEmbedder */\nexport interface OpenAIEmbedderOptions {\n apiKey: string;\n model?: string;\n dimensions?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** @default 30000 */\n timeoutMs?: number;\n}\n\n/**\n * Create an EmbedderFn that calls the OpenAI embeddings API.\n *\n * @example\n * ```typescript\n * const embedder = createOpenAIEmbedder({ apiKey: process.env.OPENAI_API_KEY! });\n * const embedding = await embedder('How do constraints work?');\n * ```\n */\nexport function createOpenAIEmbedder(\n options: OpenAIEmbedderOptions,\n): EmbedderFn {\n const {\n apiKey,\n model = \"text-embedding-3-small\",\n dimensions = 1536,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n timeoutMs,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIEmbedder\");\n\n return async (text: string): Promise<Embedding> => {\n const response = await fetchFn(`${baseURL}/embeddings`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({ model, input: text, dimensions }),\n signal: AbortSignal.timeout(timeoutMs ?? 30_000),\n });\n\n if (!response.ok) {\n const errBody = await response.text().catch(() => \"\");\n\n throw new Error(\n `[Directive] OpenAI embedding failed: ${response.status}${errBody ? ` – ${errBody.slice(0, 200)}` : \"\"}`,\n );\n }\n\n const data = (await response.json()) as {\n data: Array<{ embedding: number[] }>;\n };\n\n const entry = data.data[0];\n if (!entry) {\n throw new Error(\n \"[Directive] OpenAI embedding response contained no data entries\",\n );\n }\n\n return entry.embedding;\n };\n}\n\n// ============================================================================\n// OpenAI Streaming Runner\n// ============================================================================\n\n/** Options for createOpenAIStreamingRunner */\nexport interface OpenAIStreamingRunnerOptions {\n apiKey: string;\n model?: string;\n maxTokens?: number;\n baseURL?: string;\n fetch?: typeof globalThis.fetch;\n /** Lifecycle hooks for tracing, logging, and metrics */\n hooks?: AdapterHooks;\n /** Sampling temperature (0–2). Higher = more random. */\n temperature?: number;\n /** Nucleus sampling: top-P probability mass (0–1). */\n topP?: number;\n /** Up to 4 sequences where the API will stop generating. */\n stop?: string | string[];\n /**\n * Response format for structured output.\n * - `\"json\"` enables JSON mode (`{ type: \"json_object\" }`)\n * - Object form enables JSON Schema mode (`{ type: \"json_schema\", json_schema: ... }`)\n */\n responseFormat?: \"json\" | { type: \"json_schema\"; json_schema: unknown };\n}\n\n/**\n * Create a StreamingCallbackRunner for OpenAI-compatible chat completions\n * with server-sent events. Can be used standalone or paired with `createOpenAIRunner`.\n *\n * Returns `tokenUsage` with input/output breakdown for cost tracking.\n *\n * @example\n * ```typescript\n * const streamingRunner = createOpenAIStreamingRunner({\n * apiKey: process.env.OPENAI_API_KEY!,\n * });\n * const streamRunner = createStreamingRunner(streamingRunner);\n * const { stream, result } = streamRunner(agent, input);\n * ```\n */\nexport function createOpenAIStreamingRunner(\n options: OpenAIStreamingRunnerOptions,\n): StreamingCallbackRunner {\n const {\n apiKey,\n model = \"gpt-4o\",\n maxTokens,\n baseURL = \"https://api.openai.com/v1\",\n fetch: fetchFn = globalThis.fetch,\n hooks,\n temperature,\n topP,\n stop,\n responseFormat,\n } = options;\n\n validateBaseURL(baseURL);\n warnIfMissingApiKey(apiKey, \"createOpenAIStreamingRunner\");\n\n const resolvedResponseFormat =\n responseFormat === \"json\"\n ? { type: \"json_object\" as const }\n : (responseFormat ?? undefined);\n\n return async (agent, input, callbacks) => {\n const startTime = fireBeforeCallHook(hooks, agent, input);\n\n try {\n const response = await fetchFn(`${baseURL}/chat/completions`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${apiKey}`,\n },\n body: JSON.stringify({\n model: agent.model ?? model,\n ...(maxTokens != null ? { max_tokens: maxTokens } : {}),\n ...(temperature != null ? { temperature } : {}),\n ...(topP != null ? { top_p: topP } : {}),\n ...(stop != null ? { stop } : {}),\n ...(resolvedResponseFormat != null\n ? { response_format: resolvedResponseFormat }\n : {}),\n messages: [\n ...(agent.instructions\n ? [{ role: \"system\", content: agent.instructions }]\n : []),\n { role: \"user\", content: input },\n ],\n stream: true,\n stream_options: { include_usage: true },\n }),\n signal: callbacks.signal,\n });\n\n if (!response.ok) {\n await throwStreamingHTTPError(response, \"OpenAI\");\n }\n\n const reader = getSSEReader(response);\n\n const { fullText, inputTokens, outputTokens } = await parseSSEStream(\n reader,\n callbacks.onToken,\n (event) => {\n const result: {\n text?: string;\n inputTokens?: number;\n outputTokens?: number;\n } = {};\n\n const delta = (event.choices as Array<Record<string, unknown>>)?.[0]\n ?.delta as Record<string, unknown> | undefined;\n if (delta?.content) {\n result.text = delta.content as string;\n }\n\n if (event.usage) {\n result.inputTokens =\n ((event.usage as Record<string, unknown>)\n .prompt_tokens as number) ?? 0;\n result.outputTokens =\n ((event.usage as Record<string, unknown>)\n .completion_tokens as number) ?? 0;\n }\n\n return result;\n },\n \"OpenAI\",\n );\n\n const tokenUsage = { inputTokens, outputTokens };\n const totalTokens = inputTokens + outputTokens;\n\n callbacks.onMessage?.({ role: \"assistant\", content: fullText });\n fireAfterCallHook(\n hooks,\n agent,\n input,\n fullText,\n totalTokens,\n tokenUsage,\n startTime,\n );\n\n return buildStreamingResult(input, fullText, totalTokens, tokenUsage);\n } catch (err) {\n fireErrorHook(hooks, agent, input, err, startTime);\n\n throw err;\n }\n };\n}\n"]}
|
|
@@ -1041,7 +1041,7 @@ interface AgentOrchestrator<F extends Record<string, unknown>> {
|
|
|
1041
1041
|
* guardrails: {
|
|
1042
1042
|
* input: [
|
|
1043
1043
|
* async (data) => {
|
|
1044
|
-
* const hasPII = await detectPII(data.input);
|
|
1044
|
+
* const hasPII = (await detectPII(data.input)).detected;
|
|
1045
1045
|
* return { passed: !hasPII, reason: hasPII ? 'Contains PII' : undefined };
|
|
1046
1046
|
* },
|
|
1047
1047
|
* ],
|
|
@@ -1041,7 +1041,7 @@ interface AgentOrchestrator<F extends Record<string, unknown>> {
|
|
|
1041
1041
|
* guardrails: {
|
|
1042
1042
|
* input: [
|
|
1043
1043
|
* async (data) => {
|
|
1044
|
-
* const hasPII = await detectPII(data.input);
|
|
1044
|
+
* const hasPII = (await detectPII(data.input)).detected;
|
|
1045
1045
|
* return { passed: !hasPII, reason: hasPII ? 'Contains PII' : undefined };
|
|
1046
1046
|
* },
|
|
1047
1047
|
* ],
|