| 545 | |
| 546 | // -------------------- Streaming (SSE-over-fetch) -------------------- |
| 547 | async streamSessionMessage( |
| 548 | params: { |
| 549 | query: string; |
| 550 | model?: string; |
| 551 | session_id?: string; |
| 552 | table_name?: string; |
| 553 | composeSubAnswers?: boolean; |
| 554 | decompose?: boolean; |
| 555 | aiRerank?: boolean; |
| 556 | contextExpand?: boolean; |
| 557 | verify?: boolean; |
| 558 | // ✨ NEW RETRIEVAL PARAMETERS |
| 559 | retrievalK?: number; |
| 560 | contextWindowSize?: number; |
| 561 | rerankerTopK?: number; |
| 562 | searchType?: string; |
| 563 | denseWeight?: number; |
| 564 | forceRag?: boolean; |
| 565 | provencePrune?: boolean; |
| 566 | }, |
| 567 | onEvent: (event: { type: string; data: any }) => void, |
| 568 | ): Promise<void> { |
| 569 | const { query, model, session_id, table_name, composeSubAnswers, decompose, aiRerank, contextExpand, verify, retrievalK, contextWindowSize, rerankerTopK, searchType, denseWeight, forceRag, provencePrune } = params; |
| 570 | |
| 571 | const payload: Record<string, unknown> = { query }; |
| 572 | if (model) payload.model = model; |
| 573 | if (session_id) payload.session_id = session_id; |
| 574 | if (table_name) payload.table_name = table_name; |
| 575 | if (typeof composeSubAnswers === 'boolean') payload.compose_sub_answers = composeSubAnswers; |
| 576 | if (typeof decompose === 'boolean') payload.query_decompose = decompose; |
| 577 | if (typeof aiRerank === 'boolean') payload.ai_rerank = aiRerank; |
| 578 | if (typeof contextExpand === 'boolean') payload.context_expand = contextExpand; |
| 579 | if (typeof verify === 'boolean') payload.verify = verify; |
| 580 | // ✨ ADD NEW RETRIEVAL PARAMETERS TO PAYLOAD |
| 581 | if (typeof retrievalK === 'number') payload.retrieval_k = retrievalK; |
| 582 | if (typeof contextWindowSize === 'number') payload.context_window_size = contextWindowSize; |
| 583 | if (typeof rerankerTopK === 'number') payload.reranker_top_k = rerankerTopK; |
| 584 | if (typeof searchType === 'string') payload.search_type = searchType; |
| 585 | if (typeof denseWeight === 'number') payload.dense_weight = denseWeight; |
| 586 | if (typeof forceRag === 'boolean') payload.force_rag = forceRag; |
| 587 | if (typeof provencePrune === 'boolean') payload.provence_prune = provencePrune; |
| 588 | |
| 589 | const resp = await fetch('http://localhost:8001/chat/stream', { |
| 590 | method: 'POST', |
| 591 | headers: { 'Content-Type': 'application/json' }, |
| 592 | body: JSON.stringify(payload), |
| 593 | }); |
| 594 | |
| 595 | if (!resp.ok || !resp.body) { |
| 596 | throw new Error(`Stream request failed: ${resp.status}`); |
| 597 | } |
| 598 | |
| 599 | const reader = resp.body.getReader(); |
| 600 | const decoder = new TextDecoder(); |
| 601 | let buffer = ''; |
| 602 | |
| 603 | let streamClosed = false; |
| 604 | while (!streamClosed) { |