UNPKG

zod-stream

Version:

A client for node or the browser to generate and consume streaming json

47 lines (35 loc) 8.61 kB
function J(t){let e=typeof t=="string"?JSON.parse(t):t;return e.choices?.[0]?.delta?.function_call?.arguments??e.choices?.[0]?.message?.function_call?.arguments??""}function R(t){let e=typeof t=="string"?JSON.parse(t):t;return e.choices?.[0]?.delta?.tool_calls?.[0]?.function?.arguments??e.choices?.[0]?.message?.tool_calls?.[0]?.function?.arguments??""}function _(t){let e=typeof t=="string"?JSON.parse(t):t,o=e.choices?.[0]?.delta?.content??e?.choices?.[0]?.message?.content??"",n=/```json\n([\s\S]*?)\n```/,r=o.match(n);return r?r[1]:o}function u(t){let e=typeof t=="string"?JSON.parse(t):t,o=e.choices?.[0]?.delta?.function_call?.arguments||e.choices?.[0]?.message?.function_call?.arguments||!1,n=e.choices?.[0]?.delta?.tool_calls?.[0]?.function?.arguments??e.choices?.[0]?.message?.tool_calls?.[0]?.function?.arguments??!1;return o?J(t):n?R(t):_(t)}function A(t){return t.replace(/[\x00-\x1F\x7F-\x9F]/g,"")}function T({res:t}){let e,o=new TextEncoder;async function*n(a){let i=!1;e=()=>{i=!0};for await(let s of a){if(i)break;u(s)&&(yield u(s))}}let r=n(t);return new ReadableStream({async start(a){for await(let i of r)a.enqueue(o.encode(A(i)));a.close()},cancel(){e&&e()}})}async function*S(t){let e=t.getReader(),o=new TextDecoder;for(;;){let{done:n,value:r}=await e.read();if(n)break;let a=A(o.decode(r));yield JSON.parse(a)}}import{SchemaStream as I}from"schema-stream";var d=class{constructor({debug:e=!1}={}){this.debug=!1;this.debug=e}log(e,...o){if(!this.debug&&e==="debug")return;let n=new Date().toISOString();switch(e){case"debug":console.debug(`[ZodStream-CLIENT:DEBUG] ${n}:`,...o);break;case"info":console.info(`[ZodStream-CLIENT:INFO] ${n}:`,...o);break;case"warn":console.warn(`[ZodStream-CLIENT:WARN] ${n}:`,...o);break;case"error":console.error(`[ZodStream-CLIENT:ERROR] ${n}:`,...o);break}}async chatCompletionStream({completionPromise:e,data:o,response_model:n}){let r=[],a=[];this.log("debug","Starting completion stream");let i=new I(n.schema,{typeDefaults:{string:null,number:null,boolean:null},onKeyComplete:({activePath:s,completedPaths:c})=>{this.log("debug","Key complete",s,c),r=s,a=c}});try{let s=i.parse({handleUnescapedNewLines:!0}),c=new TextEncoder,m=new TextDecoder,h=new TransformStream({transform:async(O,P)=>{try{let l=JSON.parse(m.decode(O)),y=await n.schema.safeParseAsync(l);this.log("debug","Validation result",y),P.enqueue(c.encode(JSON.stringify({...l,_meta:{_isValid:y.success,_activePath:r,_completedPaths:a}})))}catch(l){this.log("error","Error in the partial stream validation stream",l,O),P.error(l)}},flush(){}}),f=await e(o);if(!f)throw this.log("error","Completion call returned no data"),new Error(f);return f.pipeThrough(s),s.readable.pipeThrough(h),S(h.readable)}catch(s){throw this.log("error","Error making completion call"),s}}getSchemaStub({schema:e,defaultData:o={}}){return new I(e,{defaultData:o,typeDefaults:{string:null,number:null,boolean:null}}).getSchemaStub(e,o)}async create(e){return this.chatCompletionStream(e)}};function x(t,e){let o={};for(let n in e)e.hasOwnProperty(n)&&!t.includes(n)&&(o[n]=e[n]);return o}function M(t,e){let{name:o,description:n,...r}=t,a={name:o},i=[...e?.functions??[],{name:o,description:n??void 0,parameters:r}];return{...e,function_call:a,functions:i}}function w(t,e){let{name:o,description:n,...r}=t,a={type:"function",function:{name:o}},i=[{type:"function",function:{name:o,description:n,parameters:r}},...e.tools?.map(s=>({type:s.type,function:{name:s.function.name,description:s.function.description,parameters:s.function.parameters}}))??[]];return{...e,tool_choice:a,tools:i}}function C(t,e){return{...e,messages:[{role:"system",content:` Given a user prompt, you will return fully valid JSON based on the following description and schema. You will return no other prose. You will take into account any descriptions or required parameters within the schema and return a valid and fully escaped JSON object that matches the schema and those instructions. description: ${t.description} json schema: ${JSON.stringify(t)} `},...e.messages]}}function N(t,e){return{...e,messages:[{role:"system",content:` Given a user prompt, you will return fully valid JSON based on the provided description and schema. You will take into account any descriptions or required parameters within the schema and return a valid and fully escaped JSON object that matches the schema and those instructions. You will always return your full thought process in one <think> tag and then return the JSON response in a \`\`\`json block after the </think> tag. Never include any prose or thinking process outside of the <think> tag. For example: <think> I am analyzing the input to extract the required information... </think> \`\`\`json { "result": "the actual json response" } \`\`\` description: ${t.description} json schema: ${JSON.stringify(t)} `},...e.messages]}}function b(t,e){return{...e,response_format:{type:"json_object"},messages:[{role:"system",content:` Given a user prompt, you will return fully valid JSON based on the following description and schema. You will return no other prose. You will take into account any descriptions or required parameters within the schema and return a valid and fully escaped JSON object that matches the schema and those instructions. description: ${t.description} json schema: ${JSON.stringify(t)} `},...e.messages]}}function k(t,e){return{...e,response_format:{type:"json_object",schema:x(["name","description"],t)},messages:[{role:"system",content:` Given a user prompt, you will return fully valid JSON based on the following description. You will return no other prose. You will take into account any descriptions or required parameters within the schema and return a valid and fully escaped JSON object that matches the schema and those instructions. description: ${t.description} `},...e.messages]}}import j from"zod-to-json-schema";var p={FUNCTIONS:"FUNCTIONS",TOOLS:"TOOLS",JSON:"JSON",MD_JSON:"MD_JSON",JSON_SCHEMA:"JSON_SCHEMA",THINKING_MD_JSON:"THINKING_MD_JSON"};function g({response_model:{name:t,schema:e,description:o=""},mode:n,params:r}){let a=t.replace(/[^a-zA-Z0-9]/g,"_").replace(/\s/g,"_"),{definitions:i}=j(e,{name:a,errorMessages:!0});if(!i||!i?.[a])throw console.warn("Could not extract json schema definitions from your schema",e),new Error("Could not extract json schema definitions from your schema");let s={name:a,description:o,...i[a]};return n===p.FUNCTIONS?M(s,r):n===p.TOOLS?w(s,r):n===p.JSON?b(s,r):n===p.JSON_SCHEMA?k(s,r):n===p.MD_JSON?C(s,r):n===p.THINKING_MD_JSON?N(s,r):C(s,r)}function Q({defaultClientOptions:t,response_model:e,mode:o="TOOLS",client:n}){let r={temperature:.7,top_p:1,frequency_penalty:0,presence_penalty:0,n:1,...t};if(!n)throw new Error("an OpenAI-like client is required");let a=n;return{completionStream:async i=>{let s=[...r.messages??[],...i?.messages??[]],c=g({mode:o,response_model:e,params:{...r,...i,stream:!0,messages:s}}),m=await a.chat.completions.create(c);return T({res:m})},completion:async i=>{let s=[...r.messages??[],...i?.messages??[]],c=g({mode:o,response_model:e,params:{...r,...i,stream:!1,messages:s}}),m=await a.chat.completions.create(c),h=u(m);return JSON.parse(h)}}}function ee(t,e){let{_completedPaths:o}=e?._meta??{};return o.some(n=>n.length!==t.length?!1:n.every((r,a)=>{let i=t[a];return r===void 0||i===void 0?!0:r===i}))}function ne(t){let e=typeof t=="string"?t:"choices"in t&&t.choices?.[0]?t.choices[0].message?.content??"":"",o=/<think(?:ing)?>([\s\S]*?)(?:<\/think(?:ing)?>|\Z)/i,n=e.match(o),r=n?n[1].trim():"",a=e.replace(o,"").trim();if(a.trim().startsWith("{")||a.trim().startsWith("["))return{json:a.trim(),thinking:r};let i=/```(?:json)?\s*([\s\S]*?)```/,s=a.match(i);if(s)return{json:s[1].trim(),thinking:r};let c=a.match(/```(?:json)?\s*([\s\S]*)/i);if(c){let m=c[1].trim();if(m.startsWith("{")||m.startsWith("["))return{json:m,thinking:r}}return{json:"",thinking:r}}var se=d;export{p as MODE,J as OAIResponseFnArgsParser,_ as OAIResponseJSONParser,u as OAIResponseParser,R as OAIResponseToolArgsParser,T as OAIStream,Q as createAgent,se as default,ee as isPathComplete,S as readableStreamToAsyncGenerator,ne as thinkingJsonParser,g as withResponseModel}; //# sourceMappingURL=index.js.map