parser.js 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.isChatCompletionFunctionTool = isChatCompletionFunctionTool;
  4. exports.makeParseableResponseFormat = makeParseableResponseFormat;
  5. exports.makeParseableTextFormat = makeParseableTextFormat;
  6. exports.isAutoParsableResponseFormat = isAutoParsableResponseFormat;
  7. exports.makeParseableTool = makeParseableTool;
  8. exports.isAutoParsableTool = isAutoParsableTool;
  9. exports.maybeParseChatCompletion = maybeParseChatCompletion;
  10. exports.parseChatCompletion = parseChatCompletion;
  11. exports.shouldParseToolCall = shouldParseToolCall;
  12. exports.hasAutoParseableInput = hasAutoParseableInput;
  13. exports.assertToolCallsAreChatCompletionFunctionToolCalls = assertToolCallsAreChatCompletionFunctionToolCalls;
  14. exports.validateInputTools = validateInputTools;
  15. const error_1 = require("../error.js");
  16. function isChatCompletionFunctionTool(tool) {
  17. return tool !== undefined && 'function' in tool && tool.function !== undefined;
  18. }
  19. function makeParseableResponseFormat(response_format, parser) {
  20. const obj = { ...response_format };
  21. Object.defineProperties(obj, {
  22. $brand: {
  23. value: 'auto-parseable-response-format',
  24. enumerable: false,
  25. },
  26. $parseRaw: {
  27. value: parser,
  28. enumerable: false,
  29. },
  30. });
  31. return obj;
  32. }
  33. function makeParseableTextFormat(response_format, parser) {
  34. const obj = { ...response_format };
  35. Object.defineProperties(obj, {
  36. $brand: {
  37. value: 'auto-parseable-response-format',
  38. enumerable: false,
  39. },
  40. $parseRaw: {
  41. value: parser,
  42. enumerable: false,
  43. },
  44. });
  45. return obj;
  46. }
  47. function isAutoParsableResponseFormat(response_format) {
  48. return response_format?.['$brand'] === 'auto-parseable-response-format';
  49. }
  50. function makeParseableTool(tool, { parser, callback, }) {
  51. const obj = { ...tool };
  52. Object.defineProperties(obj, {
  53. $brand: {
  54. value: 'auto-parseable-tool',
  55. enumerable: false,
  56. },
  57. $parseRaw: {
  58. value: parser,
  59. enumerable: false,
  60. },
  61. $callback: {
  62. value: callback,
  63. enumerable: false,
  64. },
  65. });
  66. return obj;
  67. }
  68. function isAutoParsableTool(tool) {
  69. return tool?.['$brand'] === 'auto-parseable-tool';
  70. }
  71. function maybeParseChatCompletion(completion, params) {
  72. if (!params || !hasAutoParseableInput(params)) {
  73. return {
  74. ...completion,
  75. choices: completion.choices.map((choice) => {
  76. assertToolCallsAreChatCompletionFunctionToolCalls(choice.message.tool_calls);
  77. return {
  78. ...choice,
  79. message: {
  80. ...choice.message,
  81. parsed: null,
  82. ...(choice.message.tool_calls ?
  83. {
  84. tool_calls: choice.message.tool_calls,
  85. }
  86. : undefined),
  87. },
  88. };
  89. }),
  90. };
  91. }
  92. return parseChatCompletion(completion, params);
  93. }
  94. function parseChatCompletion(completion, params) {
  95. const choices = completion.choices.map((choice) => {
  96. if (choice.finish_reason === 'length') {
  97. throw new error_1.LengthFinishReasonError();
  98. }
  99. if (choice.finish_reason === 'content_filter') {
  100. throw new error_1.ContentFilterFinishReasonError();
  101. }
  102. assertToolCallsAreChatCompletionFunctionToolCalls(choice.message.tool_calls);
  103. return {
  104. ...choice,
  105. message: {
  106. ...choice.message,
  107. ...(choice.message.tool_calls ?
  108. {
  109. tool_calls: choice.message.tool_calls?.map((toolCall) => parseToolCall(params, toolCall)) ?? undefined,
  110. }
  111. : undefined),
  112. parsed: choice.message.content && !choice.message.refusal ?
  113. parseResponseFormat(params, choice.message.content)
  114. : null,
  115. },
  116. };
  117. });
  118. return { ...completion, choices };
  119. }
  120. function parseResponseFormat(params, content) {
  121. if (params.response_format?.type !== 'json_schema') {
  122. return null;
  123. }
  124. if (params.response_format?.type === 'json_schema') {
  125. if ('$parseRaw' in params.response_format) {
  126. const response_format = params.response_format;
  127. return response_format.$parseRaw(content);
  128. }
  129. return JSON.parse(content);
  130. }
  131. return null;
  132. }
  133. function parseToolCall(params, toolCall) {
  134. const inputTool = params.tools?.find((inputTool) => isChatCompletionFunctionTool(inputTool) && inputTool.function?.name === toolCall.function.name); // TS doesn't narrow based on isChatCompletionTool
  135. return {
  136. ...toolCall,
  137. function: {
  138. ...toolCall.function,
  139. parsed_arguments: isAutoParsableTool(inputTool) ? inputTool.$parseRaw(toolCall.function.arguments)
  140. : inputTool?.function.strict ? JSON.parse(toolCall.function.arguments)
  141. : null,
  142. },
  143. };
  144. }
  145. function shouldParseToolCall(params, toolCall) {
  146. if (!params || !('tools' in params) || !params.tools) {
  147. return false;
  148. }
  149. const inputTool = params.tools?.find((inputTool) => isChatCompletionFunctionTool(inputTool) && inputTool.function?.name === toolCall.function.name);
  150. return (isChatCompletionFunctionTool(inputTool) &&
  151. (isAutoParsableTool(inputTool) || inputTool?.function.strict || false));
  152. }
  153. function hasAutoParseableInput(params) {
  154. if (isAutoParsableResponseFormat(params.response_format)) {
  155. return true;
  156. }
  157. return (params.tools?.some((t) => isAutoParsableTool(t) || (t.type === 'function' && t.function.strict === true)) ?? false);
  158. }
  159. function assertToolCallsAreChatCompletionFunctionToolCalls(toolCalls) {
  160. for (const toolCall of toolCalls || []) {
  161. if (toolCall.type !== 'function') {
  162. throw new error_1.OpenAIError(`Currently only \`function\` tool calls are supported; Received \`${toolCall.type}\``);
  163. }
  164. }
  165. }
  166. function validateInputTools(tools) {
  167. for (const tool of tools ?? []) {
  168. if (tool.type !== 'function') {
  169. throw new error_1.OpenAIError(`Currently only \`function\` tool types support auto-parsing; Received \`${tool.type}\``);
  170. }
  171. if (tool.function.strict !== true) {
  172. throw new error_1.OpenAIError(`The \`${tool.function.name}\` tool is not marked with \`strict: true\`. Only strict function tools can be auto-parsed`);
  173. }
  174. }
  175. }
  176. //# sourceMappingURL=parser.js.map