| 295 | |
| 296 | // Stream generators |
| 297 | async function* retoolStreamGenerator( |
| 298 | fullMessage: string, |
| 299 | modelId: string, |
| 300 | ) { |
| 301 | const streamId = crypto.randomUUID(); |
| 302 | const created = Math.floor(Date.now() / 1000); |
| 303 | const header = JSON.stringify({ |
| 304 | id: streamId, |
| 305 | object: "chat.completion.chunk", |
| 306 | created, |
| 307 | model: modelId, |
| 308 | choices: [{ delta: { role: "assistant" }, index: 0 }], |
| 309 | }); |
| 310 | yield `data: ${header}\n\n`; |
| 311 | |
| 312 | const chunkSize = 5; |
| 313 | for (let i = 0; i < fullMessage.length; i += chunkSize) { |
| 314 | const part = fullMessage.slice(i, i + chunkSize); |
| 315 | const body = JSON.stringify({ |
| 316 | id: streamId, |
| 317 | object: "chat.completion.chunk", |
| 318 | created, |
| 319 | model: modelId, |
| 320 | choices: [{ delta: { content: part }, index: 0 }], |
| 321 | }); |
| 322 | yield `data: ${body}\n\n`; |
| 323 | await new Promise((r) => setTimeout(r, 10)); |
| 324 | } |
| 325 | const done = JSON.stringify({ |
| 326 | id: streamId, |
| 327 | object: "chat.completion.chunk", |
| 328 | created, |
| 329 | model: modelId, |
| 330 | choices: [{ delta: {}, index: 0, finish_reason: "stop" }], |
| 331 | }); |
| 332 | yield `data: ${done}\n\ndata: [DONE]\n\n`; |
| 333 | } |
| 334 | async function* errorStreamGenerator(msg: string, code = 503) { |
| 335 | yield `data: ${JSON.stringify({ error: { message: msg, code } })}\n\n`; |
| 336 | yield "data: [DONE]\n\n"; |