ResponseStream.mjs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. var _ResponseStream_instances, _ResponseStream_params, _ResponseStream_currentResponseSnapshot, _ResponseStream_finalResponse, _ResponseStream_beginRequest, _ResponseStream_addEvent, _ResponseStream_endRequest, _ResponseStream_accumulateResponse;
  2. import { __classPrivateFieldGet, __classPrivateFieldSet } from "../../internal/tslib.mjs";
  3. import { APIUserAbortError, OpenAIError } from "../../error.mjs";
  4. import { EventStream } from "../EventStream.mjs";
  5. import { maybeParseResponse } from "../ResponsesParser.mjs";
  6. export class ResponseStream extends EventStream {
  7. constructor(params) {
  8. super();
  9. _ResponseStream_instances.add(this);
  10. _ResponseStream_params.set(this, void 0);
  11. _ResponseStream_currentResponseSnapshot.set(this, void 0);
  12. _ResponseStream_finalResponse.set(this, void 0);
  13. __classPrivateFieldSet(this, _ResponseStream_params, params, "f");
  14. }
  15. static createResponse(client, params, options) {
  16. const runner = new ResponseStream(params);
  17. runner._run(() => runner._createOrRetrieveResponse(client, params, {
  18. ...options,
  19. headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' },
  20. }));
  21. return runner;
  22. }
  23. async _createOrRetrieveResponse(client, params, options) {
  24. const signal = options?.signal;
  25. if (signal) {
  26. if (signal.aborted)
  27. this.controller.abort();
  28. signal.addEventListener('abort', () => this.controller.abort());
  29. }
  30. __classPrivateFieldGet(this, _ResponseStream_instances, "m", _ResponseStream_beginRequest).call(this);
  31. let stream;
  32. let starting_after = null;
  33. if ('response_id' in params) {
  34. stream = await client.responses.retrieve(params.response_id, { stream: true }, { ...options, signal: this.controller.signal, stream: true });
  35. starting_after = params.starting_after ?? null;
  36. }
  37. else {
  38. stream = await client.responses.create({ ...params, stream: true }, { ...options, signal: this.controller.signal });
  39. }
  40. this._connected();
  41. for await (const event of stream) {
  42. __classPrivateFieldGet(this, _ResponseStream_instances, "m", _ResponseStream_addEvent).call(this, event, starting_after);
  43. }
  44. if (stream.controller.signal?.aborted) {
  45. throw new APIUserAbortError();
  46. }
  47. return __classPrivateFieldGet(this, _ResponseStream_instances, "m", _ResponseStream_endRequest).call(this);
  48. }
  49. [(_ResponseStream_params = new WeakMap(), _ResponseStream_currentResponseSnapshot = new WeakMap(), _ResponseStream_finalResponse = new WeakMap(), _ResponseStream_instances = new WeakSet(), _ResponseStream_beginRequest = function _ResponseStream_beginRequest() {
  50. if (this.ended)
  51. return;
  52. __classPrivateFieldSet(this, _ResponseStream_currentResponseSnapshot, undefined, "f");
  53. }, _ResponseStream_addEvent = function _ResponseStream_addEvent(event, starting_after) {
  54. if (this.ended)
  55. return;
  56. const maybeEmit = (name, event) => {
  57. if (starting_after == null || event.sequence_number > starting_after) {
  58. this._emit(name, event);
  59. }
  60. };
  61. const response = __classPrivateFieldGet(this, _ResponseStream_instances, "m", _ResponseStream_accumulateResponse).call(this, event);
  62. maybeEmit('event', event);
  63. switch (event.type) {
  64. case 'response.output_text.delta': {
  65. const output = response.output[event.output_index];
  66. if (!output) {
  67. throw new OpenAIError(`missing output at index ${event.output_index}`);
  68. }
  69. if (output.type === 'message') {
  70. const content = output.content[event.content_index];
  71. if (!content) {
  72. throw new OpenAIError(`missing content at index ${event.content_index}`);
  73. }
  74. if (content.type !== 'output_text') {
  75. throw new OpenAIError(`expected content to be 'output_text', got ${content.type}`);
  76. }
  77. maybeEmit('response.output_text.delta', {
  78. ...event,
  79. snapshot: content.text,
  80. });
  81. }
  82. break;
  83. }
  84. case 'response.function_call_arguments.delta': {
  85. const output = response.output[event.output_index];
  86. if (!output) {
  87. throw new OpenAIError(`missing output at index ${event.output_index}`);
  88. }
  89. if (output.type === 'function_call') {
  90. maybeEmit('response.function_call_arguments.delta', {
  91. ...event,
  92. snapshot: output.arguments,
  93. });
  94. }
  95. break;
  96. }
  97. default:
  98. maybeEmit(event.type, event);
  99. break;
  100. }
  101. }, _ResponseStream_endRequest = function _ResponseStream_endRequest() {
  102. if (this.ended) {
  103. throw new OpenAIError(`stream has ended, this shouldn't happen`);
  104. }
  105. const snapshot = __classPrivateFieldGet(this, _ResponseStream_currentResponseSnapshot, "f");
  106. if (!snapshot) {
  107. throw new OpenAIError(`request ended without sending any events`);
  108. }
  109. __classPrivateFieldSet(this, _ResponseStream_currentResponseSnapshot, undefined, "f");
  110. const parsedResponse = finalizeResponse(snapshot, __classPrivateFieldGet(this, _ResponseStream_params, "f"));
  111. __classPrivateFieldSet(this, _ResponseStream_finalResponse, parsedResponse, "f");
  112. return parsedResponse;
  113. }, _ResponseStream_accumulateResponse = function _ResponseStream_accumulateResponse(event) {
  114. let snapshot = __classPrivateFieldGet(this, _ResponseStream_currentResponseSnapshot, "f");
  115. if (!snapshot) {
  116. if (event.type !== 'response.created') {
  117. throw new OpenAIError(`When snapshot hasn't been set yet, expected 'response.created' event, got ${event.type}`);
  118. }
  119. snapshot = __classPrivateFieldSet(this, _ResponseStream_currentResponseSnapshot, event.response, "f");
  120. return snapshot;
  121. }
  122. switch (event.type) {
  123. case 'response.output_item.added': {
  124. snapshot.output.push(event.item);
  125. break;
  126. }
  127. case 'response.content_part.added': {
  128. const output = snapshot.output[event.output_index];
  129. if (!output) {
  130. throw new OpenAIError(`missing output at index ${event.output_index}`);
  131. }
  132. const type = output.type;
  133. const part = event.part;
  134. if (type === 'message' && part.type !== 'reasoning_text') {
  135. output.content.push(part);
  136. }
  137. else if (type === 'reasoning' && part.type === 'reasoning_text') {
  138. if (!output.content) {
  139. output.content = [];
  140. }
  141. output.content.push(part);
  142. }
  143. break;
  144. }
  145. case 'response.output_text.delta': {
  146. const output = snapshot.output[event.output_index];
  147. if (!output) {
  148. throw new OpenAIError(`missing output at index ${event.output_index}`);
  149. }
  150. if (output.type === 'message') {
  151. const content = output.content[event.content_index];
  152. if (!content) {
  153. throw new OpenAIError(`missing content at index ${event.content_index}`);
  154. }
  155. if (content.type !== 'output_text') {
  156. throw new OpenAIError(`expected content to be 'output_text', got ${content.type}`);
  157. }
  158. content.text += event.delta;
  159. }
  160. break;
  161. }
  162. case 'response.function_call_arguments.delta': {
  163. const output = snapshot.output[event.output_index];
  164. if (!output) {
  165. throw new OpenAIError(`missing output at index ${event.output_index}`);
  166. }
  167. if (output.type === 'function_call') {
  168. output.arguments += event.delta;
  169. }
  170. break;
  171. }
  172. case 'response.reasoning_text.delta': {
  173. const output = snapshot.output[event.output_index];
  174. if (!output) {
  175. throw new OpenAIError(`missing output at index ${event.output_index}`);
  176. }
  177. if (output.type === 'reasoning') {
  178. const content = output.content?.[event.content_index];
  179. if (!content) {
  180. throw new OpenAIError(`missing content at index ${event.content_index}`);
  181. }
  182. if (content.type !== 'reasoning_text') {
  183. throw new OpenAIError(`expected content to be 'reasoning_text', got ${content.type}`);
  184. }
  185. content.text += event.delta;
  186. }
  187. break;
  188. }
  189. case 'response.completed': {
  190. __classPrivateFieldSet(this, _ResponseStream_currentResponseSnapshot, event.response, "f");
  191. break;
  192. }
  193. }
  194. return snapshot;
  195. }, Symbol.asyncIterator)]() {
  196. const pushQueue = [];
  197. const readQueue = [];
  198. let done = false;
  199. this.on('event', (event) => {
  200. const reader = readQueue.shift();
  201. if (reader) {
  202. reader.resolve(event);
  203. }
  204. else {
  205. pushQueue.push(event);
  206. }
  207. });
  208. this.on('end', () => {
  209. done = true;
  210. for (const reader of readQueue) {
  211. reader.resolve(undefined);
  212. }
  213. readQueue.length = 0;
  214. });
  215. this.on('abort', (err) => {
  216. done = true;
  217. for (const reader of readQueue) {
  218. reader.reject(err);
  219. }
  220. readQueue.length = 0;
  221. });
  222. this.on('error', (err) => {
  223. done = true;
  224. for (const reader of readQueue) {
  225. reader.reject(err);
  226. }
  227. readQueue.length = 0;
  228. });
  229. return {
  230. next: async () => {
  231. if (!pushQueue.length) {
  232. if (done) {
  233. return { value: undefined, done: true };
  234. }
  235. return new Promise((resolve, reject) => readQueue.push({ resolve, reject })).then((event) => (event ? { value: event, done: false } : { value: undefined, done: true }));
  236. }
  237. const event = pushQueue.shift();
  238. return { value: event, done: false };
  239. },
  240. return: async () => {
  241. this.abort();
  242. return { value: undefined, done: true };
  243. },
  244. };
  245. }
  246. /**
  247. * @returns a promise that resolves with the final Response, or rejects
  248. * if an error occurred or the stream ended prematurely without producing a REsponse.
  249. */
  250. async finalResponse() {
  251. await this.done();
  252. const response = __classPrivateFieldGet(this, _ResponseStream_finalResponse, "f");
  253. if (!response)
  254. throw new OpenAIError('stream ended without producing a ChatCompletion');
  255. return response;
  256. }
  257. }
  258. function finalizeResponse(snapshot, params) {
  259. return maybeParseResponse(snapshot, params);
  260. }
  261. //# sourceMappingURL=ResponseStream.mjs.map