51 lines
1.7 KiB
TypeScript
51 lines
1.7 KiB
TypeScript
/**
|
|||
|
|
* Mock stand-in for the real atlas `POST /api/chat`. Streams the same SSE event shape
|
||
|
|
* (`queue` → `reasoning` → `content` → `done`) as the real endpoint would, but replays a
|
||
|
|
* canned reply instead of calling vLLM — no rate limiting, no budget, no real model.
|
||
|
|
*/
|
||
|
|
const REPLY_REASONING =
|
||
|
|
'The user is asking about a gap in the wave column display. Argo CD sync waves are integers used purely for ordering; there is no requirement that they be contiguous. The cluster uses 0,1,2,3,5,6,7,8. This is normal and usually happens when a wave is retired or intentionally reserved.'
|
||
|
|
|
||
|
|
const REPLY =
|
||
|
|
'Wave 4 is empty. Waves are sort keys, not a sequence — Argo orders by value and skips gaps, so 3 is followed directly by 5. Nothing is missing.'
|
||
|
|
|
||
|
|
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
|
||
|
|
|
||
|
|
export async function POST() {
|
||
|
|
const encoder = new TextEncoder()
|
||
|
|
|
||
|
|
const stream = new ReadableStream({
|
||
|
|
async start(controller) {
|
||
|
|
const send = (type: string, payload: Record<string, unknown> = {}) => {
|
||
|
|
controller.enqueue(encoder.encode(`data: ${JSON.stringify({ type, ...payload })}\n\n`))
|
||
|
|
}
|
||
|
|
|
||
|
|
for (let position = 3; position > 0; position--) {
|
||
|
|
send('queue', { position })
|
||
|
|
await wait(500)
|
||
|
|
}
|
||
|
|
|
||
|
|
send('reasoning', { text: REPLY_REASONING })
|
||
|
|
await wait(200)
|
||
|
|
|
||
|
|
let i = 0
|
||
|
|
while (i < REPLY.length) {
|
||
|
|
i += 3
|
||
|
|
send('content', { text: REPLY.slice(0, i) })
|
||
|
|
await wait(40)
|
||
|
|
}
|
||
|
|
|
||
|
|
send('done')
|
||
|
|
controller.close()
|
||
|
|
},
|
||
|
|
})
|
||
|
|
|
||
|
|
return new Response(stream, {
|
||
|
|
headers: {
|
||
|
|
'Content-Type': 'text/event-stream',
|
||
|
|
'Cache-Control': 'no-cache',
|
||
|
|
Connection: 'keep-alive',
|
||
|
|
},
|
||
|
|
})
|
||
|
|
}
|