diff --git a/wevia-master.html b/wevia-master.html
index a5c33a2e3..213e0948b 100644
--- a/wevia-master.html
+++ b/wevia-master.html
@@ -354,6 +354,172 @@ async function v166ClaudePattern(message){
} finally { window.v166InProgress=false; if(window.v166HideRequested){setTimeout(()=>{thpPanel&&thpPanel.classList.remove('show');thpClear&&thpClear()},30000);} /* V174 defer 30s */ /* V169 hide-cancel guard */ }
}
+
+// ═══ V175 SSE Streaming Claude Pattern (real-time 7 phases + persistent memory) ═══
+function v175ClaudePatternSSE(message, session){
+ return new Promise((resolve) => {
+ if (typeof thpShow !== 'function') { resolve(null); return; }
+ window.v166InProgress = true;
+ window.v166HideRequested = false;
+ thpShow();
+ thpSetStage('plan');
+
+ const url = '/api/claude-pattern-sse.php?chatbot=wevia-master&memory=1&message='
+ + encodeURIComponent(message)
+ + (session ? '&session=' + encodeURIComponent(session) : '');
+
+ const es = new EventSource(url);
+ const phaseMap = {
+ thinking: {stage: 'plan', icon: '🧠'},
+ plan: {stage: 'prepare', icon: '📋'},
+ memory: {stage: 'prepare', icon: '💾'},
+ rag: {stage: 'prepare', icon: '🔗'},
+ execute: {stage: 'code', icon: '⚙'},
+ tests: {stage: 'test', icon: '🧪'},
+ response: {stage: 'commit', icon: '💬'},
+ critique: {stage: 'wiki', icon: '✅'},
+ memory_saved: {stage: 'wiki', icon: '💾'},
+ done: {stage: 'rag', icon: '📊'}
+ };
+
+ let timeout = setTimeout(() => { try { es.close(); } catch(e){} resolve(null); }, 30000);
+
+ ['thinking','plan','memory','rag','execute','tests','response','critique','memory_saved','done'].forEach(evt => {
+ es.addEventListener(evt, (e) => {
+ try {
+ const data = JSON.parse(e.data);
+ const m = phaseMap[evt] || {stage: 'plan', icon: '•'};
+ thpSetStage(m.stage);
+ let detail = '';
+ if (evt === 'thinking') detail = `${data.detected_intent||''} · ${data.complexity||''} · ${data.message_length||0} chars`;
+ else if (evt === 'plan') detail = `${data.steps_count||0} étapes · backend ${(data.backend_selected||'').split('/').pop()}`;
+ else if (evt === 'memory') detail = `scope ${data.scope||''} · ${data.contexts_loaded||0} contextes mémoire`;
+ else if (evt === 'rag') detail = `Qdrant ${data.status||''} · ${data.contexts_found||0} contextes`;
+ else if (evt === 'execute') detail = `backend ${data.backend_ok ? 'OK' : 'FAIL'} · ${data.response_size||0}B`;
+ else if (evt === 'tests') detail = `${data.passed||0}/${data.total||0} passés · ${data.score_pct||0}%`;
+ else if (evt === 'response') detail = `${data.length||0} chars finaux`;
+ else if (evt === 'critique') detail = `quality ${Math.round((data.quality_score||0)*100)}%`;
+ else if (evt === 'memory_saved') detail = `saved: ${data.saved ? 'yes' : 'no'}`;
+ else if (evt === 'done') detail = `${data.phases_executed||0} phases · ${data.total_ms||0}ms total`;
+ thpAddLine(`${m.icon} ${evt.charAt(0).toUpperCase()+evt.slice(1).replace('_',' ')}`, detail, data.duration_ms ? Math.round(data.duration_ms)+'ms' : '');
+ } catch(e) {}
+ });
+ });
+
+ es.addEventListener('error', () => {
+ clearTimeout(timeout);
+ try { es.close(); } catch(e){}
+ window.v166InProgress = false;
+ resolve(null);
+ });
+
+ // Auto-close after 'done' event
+ es.addEventListener('done', () => {
+ clearTimeout(timeout);
+ setTimeout(() => { try { es.close(); } catch(e){} }, 500);
+ window.v166InProgress = false;
+ resolve(true);
+ });
+ });
+}
+
+
+// ═══ V175 SSE Pattern streaming — real-time replaces batch v166 ═══
+function v175SSEPattern(message){
+ return new Promise((resolve) => {
+ try {
+ window.v166InProgress = true;
+ window.v166HideRequested = false;
+ thpClear(); thpShow();
+
+ const url = '/api/claude-pattern-sse.php?message=' + encodeURIComponent(message) + '&chatbot=wevia-master';
+ const es = new EventSource(url);
+ const startTs = Date.now();
+ let currentStage = null;
+
+ const mapStage = {
+ thinking: 'plan', plan: 'prepare', rag: 'prepare',
+ memory: 'prepare', execute: 'code', tests: 'test',
+ response: 'commit', critique: 'wiki', done: 'rag'
+ };
+
+ es.addEventListener('thinking', e => {
+ const d = JSON.parse(e.data);
+ thpSetStage('plan');
+ if (d.status === 'analyzing') thpAddLine('🧠 Thinking', 'analyzing · ' + (d.message_length||0) + ' chars · backend ' + (d.backend||'').split('/').pop(), '');
+ else if (d.status === 'complete') thpAddLine(' ↳', 'intent=' + d.intent, Math.round(d.duration_ms||0)+'ms');
+ });
+ es.addEventListener('plan', e => {
+ const d = JSON.parse(e.data);
+ thpSetStage('prepare');
+ if (d.status === 'building') thpAddLine('📋 Plan', 'building...', '');
+ else if (d.status === 'complete') {
+ thpAddLine(' ↳', (d.steps||[]).join(' → ').substring(0,150), Math.round(d.duration_ms||0)+'ms');
+ }
+ });
+ es.addEventListener('rag', e => {
+ const d = JSON.parse(e.data);
+ if (d.status === 'searching') thpAddLine('🔗 RAG', 'Qdrant searching...', '');
+ else thpAddLine(' ↳', d.status, Math.round(d.duration_ms||0)+'ms');
+ });
+ es.addEventListener('memory', e => {
+ const d = JSON.parse(e.data);
+ thpAddLine('💾 Memory', d.scope + ' · ' + (d.loaded||0) + ' loaded', '');
+ });
+ es.addEventListener('execute', e => {
+ const d = JSON.parse(e.data);
+ thpSetStage('code');
+ if (d.status === 'calling_backend') thpAddLine('⚙ Execute', 'backend ' + (d.backend||'').split('/').pop(), '');
+ else if (d.status === 'complete') thpAddLine(' ↳', 'HTTP ' + (d.http_code||'?') + ' · ' + (d.response_size||0) + ' bytes', Math.round(d.duration_ms||0)+'ms');
+ });
+ es.addEventListener('tests', e => {
+ const d = JSON.parse(e.data);
+ thpSetStage('test');
+ thpAddLine('🧪 Tests', (d.passed||0)+'/'+(d.total||0)+' · ' + (d.score_pct||0) + '%', Math.round(d.duration_ms||0)+'ms');
+ });
+ es.addEventListener('response', e => {
+ const d = JSON.parse(e.data);
+ thpSetStage('commit');
+ thpAddLine('💬 Response', (d.length||0) + ' chars', Math.round(d.duration_ms||0)+'ms');
+ });
+ es.addEventListener('critique', e => {
+ const d = JSON.parse(e.data);
+ thpSetStage('wiki');
+ thpAddLine('✅ Critique', 'quality ' + Math.round((d.quality_score||0)*100) + '%', Math.round(d.duration_ms||0)+'ms');
+ });
+ es.addEventListener('done', e => {
+ const d = JSON.parse(e.data);
+ thpSetStage('rag');
+ thpAddLine('📊 Done', (d.phases_executed||0) + ' phases · ' + (d.quality||''), Math.round(d.total_duration_ms||(Date.now()-startTs))+'ms total');
+ es.close();
+ window.v166InProgress = false;
+ if (window.v166HideRequested) setTimeout(() => { thpPanel&&thpPanel.classList.remove('show'); thpClear&&thpClear(); }, 30000);
+ resolve();
+ });
+ es.addEventListener('error', e => {
+ es.close();
+ window.v166InProgress = false;
+ resolve();
+ });
+ es.onerror = function() {
+ es.close();
+ window.v166InProgress = false;
+ resolve();
+ };
+
+ // Safety timeout 30s
+ setTimeout(() => {
+ es.close();
+ window.v166InProgress = false;
+ resolve();
+ }, 30000);
+ } catch(e) {
+ window.v166InProgress = false;
+ resolve();
+ }
+ });
+}
+
function q(t){inp.value=t;send()}
// Drag & drop
@@ -413,8 +579,8 @@ function hideProgress(){const pw=document.getElementById('pw');if(pw)pw.remove()
async function send(){
const text=inp.value.trim();if(!text||busy)return;
busy=true;$('sendBtn').disabled=true;inp.value='';stEl.textContent='Réflexion...';thpClear();thpShow();thpSetStage('plan');
- // V166: call claude-pattern-api in parallel for 7-phases reasoning display
- v166ClaudePattern(text).catch(()=>{});
+ // V175: call claude-pattern-sse (real-time streaming) instead of V166 batch
+ v175SSEPattern(text).catch(()=>{});
showProgress('Routing intent...', 5);
addMsg(text,'u');showTyping();