feat(observer): v15 AG Native chat relay — scanChatBodies dual strategy (#632)
- Add AG Native DOM path: #conversation + .leading-relaxed.select-text - Keep Cascade path: [data-testid=conversation-view] + [data-step-index] - Register #632 in known-issues.md (SDK+DOM both blocked for AG Native) - Bump version 0.5.50 → 0.5.51 - Add DOM analysis helper scripts
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
export function generateApprovalObserverScript(_port: number): string {
|
||||
return `
|
||||
// ── Gravity Bridge v14: Strict Scope + Junk Filter ──
|
||||
// v14: Strict 5-level DOM scope, CSS/source code/icon-glue filters, no fallback
|
||||
// ── Gravity Bridge v15: AG Native Chat Relay ──
|
||||
// v15: AG Native #conversation + .leading-relaxed.select-text chat body scanning
|
||||
(function(){
|
||||
'use strict';
|
||||
var BASE='',_obs=false,_sent={},_ready=false;
|
||||
@@ -10,7 +10,7 @@ export function generateApprovalObserverScript(_port: number): string {
|
||||
var CLEANUP_MS=300000;
|
||||
|
||||
function log(m){console.log('[GB Observer] '+m);}
|
||||
log('v14 Script loaded — Strict Scope + Junk Filter');
|
||||
log('v15 Script loaded — AG Native Chat Relay');
|
||||
|
||||
// DIAGNOSTIC BEACON: immediate POST to confirm script execution in renderer
|
||||
try {
|
||||
@@ -460,15 +460,16 @@ export function generateApprovalObserverScript(_port: number): string {
|
||||
}
|
||||
|
||||
// ══════════════════════════════════════════════════════════════════
|
||||
// v7: STEP-AWARE CHAT BODY SCANNING
|
||||
// Scans [data-step-index] elements inside [data-testid="conversation-view"]
|
||||
// Extracts AI response text while filtering UI noise
|
||||
// v15: AG-NATIVE + CASCADE DUAL CHAT BODY SCANNING
|
||||
// AG Native: #conversation > ... > .leading-relaxed.select-text
|
||||
// Cascade: [data-testid="conversation-view"] > [data-step-index]
|
||||
// ══════════════════════════════════════════════════════════════════
|
||||
|
||||
var _lastScrapedStepIndex = -1;
|
||||
var _lastStepText = '';
|
||||
var _lastStepTextTime = 0;
|
||||
var _lastStepTextSent = false;
|
||||
var _lastResponseBlockCount = 0; // track number of response blocks for AG Native
|
||||
|
||||
function extractCleanStepText(stepEl) {
|
||||
if (!stepEl) return '';
|
||||
@@ -495,7 +496,7 @@ export function generateApprovalObserverScript(_port: number): string {
|
||||
}
|
||||
|
||||
// Try to get text from markdown rendering area first
|
||||
// Look for known markdown container patterns
|
||||
// AG Native uses .leading-relaxed.select-text, Cascade uses .markdown-body/.prose
|
||||
var mdEl = clone.querySelector('.markdown-body, .prose, [class*="markdown"], [class*="rendered"]');
|
||||
var rawText = '';
|
||||
if (mdEl && mdEl.innerText && mdEl.innerText.trim().length > 10) {
|
||||
@@ -515,8 +516,80 @@ export function generateApprovalObserverScript(_port: number): string {
|
||||
// One-time DOM dump
|
||||
dumpDOMStructure();
|
||||
|
||||
// PRIMARY: Find conversation-view container
|
||||
var cv = document.querySelector('[data-testid="conversation-view"]');
|
||||
// ── STRATEGY 1: AG Native — #conversation or .antigravity-agent-side-panel ──
|
||||
var cv = document.querySelector('#conversation');
|
||||
if (!cv) {
|
||||
cv = document.querySelector('.antigravity-agent-side-panel');
|
||||
}
|
||||
|
||||
if (cv) {
|
||||
// AG Native path: find AI response blocks by class pattern
|
||||
// DOM structure: #conversation > ... > .leading-relaxed.select-text (AI response text)
|
||||
var responseBlocks = cv.querySelectorAll('.leading-relaxed.select-text');
|
||||
|
||||
if (responseBlocks.length > 0) {
|
||||
// Process the LAST (most recent) response block
|
||||
var lastBlock = responseBlocks[responseBlocks.length - 1];
|
||||
|
||||
// Skip if already scraped
|
||||
if (lastBlock.dataset.agChatScraped === 'true' || lastBlock.dataset.agChatScraped === 'pending') {
|
||||
// Check for NEW blocks since last scrape
|
||||
if (responseBlocks.length > _lastResponseBlockCount) {
|
||||
// New block appeared — process it
|
||||
for (var rbi = responseBlocks.length - 1; rbi >= 0; rbi--) {
|
||||
if (responseBlocks[rbi].dataset.agChatScraped !== 'true' && responseBlocks[rbi].dataset.agChatScraped !== 'pending') {
|
||||
lastBlock = responseBlocks[rbi];
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (lastBlock.dataset.agChatScraped === 'true' || lastBlock.dataset.agChatScraped === 'pending') return;
|
||||
} else {
|
||||
return; // Already scraped, no new blocks
|
||||
}
|
||||
}
|
||||
|
||||
var blockText = extractCleanStepText(lastBlock);
|
||||
if (blockText && blockText.length > 30) {
|
||||
// QUALITY CHECK: Skip if the text is mostly short lines (UI artifacts)
|
||||
var lines = blockText.split('\\n').filter(function(l) { return l.trim().length > 0; });
|
||||
var longLines = lines.filter(function(l) { return l.trim().length > 20; });
|
||||
if (longLines.length === 0) {
|
||||
log('AG-Native: skipped (no long lines, likely UI noise)');
|
||||
return;
|
||||
}
|
||||
|
||||
// Wait for content to stabilize (3s no change)
|
||||
if (_lastStepText !== blockText) {
|
||||
_lastStepText = blockText;
|
||||
_lastStepTextTime = Date.now();
|
||||
_lastStepTextSent = false;
|
||||
return; // Wait for next scan cycle
|
||||
}
|
||||
|
||||
if (_lastStepTextSent) return;
|
||||
if (Date.now() - _lastStepTextTime < 3000) return; // Still waiting
|
||||
|
||||
// Content is stable — send it
|
||||
_lastStepTextSent = true;
|
||||
_lastResponseBlockCount = responseBlocks.length;
|
||||
lastBlock.dataset.agChatScraped = 'pending';
|
||||
|
||||
log('AG-Native chat relay: blocks=' + responseBlocks.length + ' text=' + blockText.length + ' chars');
|
||||
(function(el, txt, count) {
|
||||
fetch(BASE + '/chat', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ text: txt, source: 'ag_native_block_' + count, block_index: count })
|
||||
}).then(function() { el.dataset.agChatScraped = 'true'; log('AG-Native chat sent OK'); })
|
||||
.catch(function(e) { el.dataset.agChatScraped = 'false'; log('AG-Native chat send error: ' + e.message); });
|
||||
})(lastBlock, blockText, responseBlocks.length);
|
||||
}
|
||||
return; // AG Native path handled — don't fall through to Cascade path
|
||||
}
|
||||
}
|
||||
|
||||
// ── STRATEGY 2: Cascade — [data-testid="conversation-view"] ──
|
||||
cv = document.querySelector('[data-testid="conversation-view"]');
|
||||
if (!cv) {
|
||||
// FALLBACK: Try older selectors
|
||||
cv = document.querySelector('[class*="conversation"], [class*="chat-container"]');
|
||||
|
||||
Reference in New Issue
Block a user