ResponseStream.js 12 KB

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