Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 24 additions & 17 deletions src/content/glow-animation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
const GLOW_STYLES_ID = 'nxtscape-glow-styles'
const GLOW_INITIALIZED_KEY = 'nxtscape-glow-initialized'
const GLOW_ENABLED_KEY = 'nxtscape-glow-enabled' // Stored in chrome.storage.local

// Glow thickness controls - adjust these to change glow intensity
const GLOW_THICKNESS = 1.0 // Multiplier for all glow values (0.5 = thinner, 1.5 = thicker)
const GLOW_OPACITY = 0.6 // Final opacity of the glow overlay (0.0 - 1.0)

// Check if already initialized to prevent duplicate listeners
if ((window as any)[GLOW_INITIALIZED_KEY]) {
Expand All @@ -23,39 +27,42 @@
if (document.getElementById(GLOW_STYLES_ID)) {
return
}


// Calculate glow values based on thickness multiplier
const t = GLOW_THICKNESS

const style = document.createElement('style')
style.id = GLOW_STYLES_ID
style.textContent = `
@keyframes nxtscape-glow-pulse {
0% {
box-shadow:
inset 0 0 42px 19px transparent,
inset 0 0 36px 16px rgba(251, 102, 24, 0.06),
inset 0 0 30px 13px rgba(251, 102, 24, 0.12),
inset 0 0 24px 10px rgba(251, 102, 24, 0.18);
inset 0 0 ${58 * t}px ${26 * t}px transparent,
inset 0 0 ${50 * t}px ${22 * t}px rgba(251, 102, 24, 0.06),
inset 0 0 ${42 * t}px ${18 * t}px rgba(251, 102, 24, 0.12),
inset 0 0 ${34 * t}px ${14 * t}px rgba(251, 102, 24, 0.18);
}
50% {
box-shadow:
inset 0 0 52px 25px transparent,
inset 0 0 46px 23px rgba(251, 102, 24, 0.10),
inset 0 0 39px 19px rgba(251, 102, 24, 0.18),
inset 0 0 33px 16px rgba(251, 102, 24, 0.24);
inset 0 0 ${72 * t}px ${35 * t}px transparent,
inset 0 0 ${64 * t}px ${32 * t}px rgba(251, 102, 24, 0.10),
inset 0 0 ${54 * t}px ${26 * t}px rgba(251, 102, 24, 0.18),
inset 0 0 ${46 * t}px ${22 * t}px rgba(251, 102, 24, 0.24);
}
100% {
box-shadow:
inset 0 0 42px 19px transparent,
inset 0 0 36px 16px rgba(251, 102, 24, 0.06),
inset 0 0 30px 13px rgba(251, 102, 24, 0.12),
inset 0 0 24px 10px rgba(251, 102, 24, 0.18);
inset 0 0 ${58 * t}px ${26 * t}px transparent,
inset 0 0 ${50 * t}px ${22 * t}px rgba(251, 102, 24, 0.06),
inset 0 0 ${42 * t}px ${18 * t}px rgba(251, 102, 24, 0.12),
inset 0 0 ${34 * t}px ${14 * t}px rgba(251, 102, 24, 0.18);
}
}

@keyframes nxtscape-glow-fade-in {
from { opacity: 0; }
to { opacity: 0.6; }
to { opacity: ${GLOW_OPACITY}; }
}

#${GLOW_OVERLAY_ID} {
position: fixed !important;
top: 0 !important;
Expand All @@ -66,7 +73,7 @@
z-index: 2147483647 !important;
opacity: 0;
will-change: opacity;
animation:
animation:
nxtscape-glow-pulse 3s ease-in-out infinite,
nxtscape-glow-fade-in 420ms cubic-bezier(0.22, 1, 0.36, 1) forwards !important;
}
Expand Down
103 changes: 73 additions & 30 deletions src/lib/agent/TeachWebSocketAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { TeachModeEventPayload } from "@/lib/pubsub/types";
import { Logging } from "@/lib/utils/Logging";
import { type SemanticWorkflow } from "@/lib/teach-mode/types";
import { GlowAnimationService } from '@/lib/services/GlowAnimationService';
import { isDevelopmentMode } from '@/config';

interface PredefinedPlan {
agentId: string;
Expand Down Expand Up @@ -177,14 +178,7 @@ ${JSON.stringify(userTrajectorySteps, null, 2)}`;
});

// Start glow animation
try {
const currentPage = await this.executionContext.browserContext.getCurrentPage();
if (currentPage?.tabId && !this.glowService.isGlowActive(currentPage.tabId)) {
await this.glowService.startGlow(currentPage.tabId);
}
} catch (error) {
Logging.log("TeachWebSocketAgent", `Could not start glow animation: ${error}`, "warning");
}
this._maybeStartGlow();

// Connect to WebSocket server
await this._connect();
Expand Down Expand Up @@ -233,7 +227,7 @@ ${JSON.stringify(userTrajectorySteps, null, 2)}`;

return new Promise((resolve, reject) => {
const connectMsgId = PubSub.generateId('teach_ws_connect');
this._emitThinking(connectMsgId, '🔗 Connecting to reasoning server...');
this._emitThinking(connectMsgId, 'Getting ready...');
Logging.log("TeachWebSocketAgent", `Connecting to ${wsUrl}`, "info");

// Create WebSocket
Expand All @@ -254,8 +248,6 @@ ${JSON.stringify(userTrajectorySteps, null, 2)}`;
// WebSocket opened
this.ws.onopen = () => {
Logging.log("TeachWebSocketAgent", "WebSocket connection opened", "info");
const openMsgId = PubSub.generateId('teach_ws_open');
this._emitThinking(openMsgId, '✅ WebSocket opened, waiting for server...');
};

// WebSocket message received
Expand All @@ -270,9 +262,6 @@ ${JSON.stringify(userTrajectorySteps, null, 2)}`;
this.sessionId = data.data?.sessionId;
this.isConnected = true;

const connectedMsgId = PubSub.generateId('teach_ws_connected');
this._emitThinking(connectedMsgId, '✅ Connected to reasoning server');

if (this.sessionId) {
Logging.log(
"TeachWebSocketAgent",
Expand Down Expand Up @@ -428,26 +417,65 @@ ${formattedSteps}`;
// Update last event time for timeout tracking
this.lastEventTime = Date.now();

this._maybeStartGlow();

// Route based on message type
if (data.type === 'connection') {
// Already handled in _connect
return;
}
const isDev = isDevelopmentMode();

if (data.type === 'completion') {
this._handleCompletion(data);
return;
}
switch (data.type) {
case 'connection':
// Already handled in _connect
break;

if (data.type === 'error') {
this._handleError(data);
return;
}
case 'completion':
this._handleCompletion(data);
break;

case 'error':
this._handleError(data);
break;

case 'init':
if (isDev && data.content) {
const msgId = PubSub.generateId('teach_ws_server');
this._emitThinking(msgId, data.content);
}
break;

// For all other types (response, tool_use, thinking, etc), emit as thinking
if (data.content) {
const thinkingMsgId = PubSub.generateId('teach_ws_server');
this._emitThinking(thinkingMsgId, data.content);
case 'thinking':
if (data.content) {
const msgId = PubSub.generateId('teach_ws_server');
this._emitThinking(msgId, data.content);
}
break;

case 'tool_use':
if (data.content) {
const msgId = PubSub.generateId('teach_ws_server');
this._emitThinking(msgId, data.content);
}
break;

case 'tool_result':
if (isDev && data.content) {
const msgId = PubSub.generateId('teach_ws_server');
this._emitThinking(msgId, data.content);
}
break;

case 'response':
if (data.content) {
const msgId = PubSub.generateId('teach_ws_server');
this._emitThinking(msgId, data.content);
}
break;

default:
if (isDev && data.content) {
Logging.log("TeachWebSocketAgent", `Unknown message type: ${data.type}`, "warning");
const msgId = PubSub.generateId('teach_ws_server');
this._emitThinking(msgId, data.content);
}
}

} catch (error) {
Expand Down Expand Up @@ -558,6 +586,21 @@ ${formattedSteps}`;
}
}

/**
* Start glow animation (fire and forget)
*/
private _maybeStartGlow(): void {
this.executionContext.browserContext.getCurrentPage()
.then(page => {
if (page?.tabId && !this.glowService.isGlowActive(page.tabId)) {
return this.glowService.startGlow(page.tabId);
}
})
.catch(error => {
Logging.log("TeachWebSocketAgent", `Could not start glow: ${error}`, "warning");
});
}

/**
* Log execution metrics
*/
Expand Down
95 changes: 68 additions & 27 deletions src/lib/agent/WebSocketAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { AbortError } from "@/lib/utils/Abortable";
import { ExecutionMetadata } from "@/lib/types/messaging";
import { Logging } from "@/lib/utils/Logging";
import { GlowAnimationService } from '@/lib/services/GlowAnimationService';
import { isDevelopmentMode } from '@/config';


interface PredefinedPlan {
Expand Down Expand Up @@ -123,14 +124,7 @@ export class WebSocketAgent {
Logging.log("WebSocketAgent", "Starting execution", "info");

// Start glow animation
try {
const currentPage = await this.executionContext.browserContext.getCurrentPage();
if (currentPage?.tabId && !this.glowService.isGlowActive(currentPage.tabId)) {
await this.glowService.startGlow(currentPage.tabId);
}
} catch (error) {
Logging.log("WebSocketAgent", `Could not start glow animation: ${error}`, "warning");
}
this._maybeStartGlow();

// Connect to WebSocket server
await this._connect();
Expand Down Expand Up @@ -177,7 +171,7 @@ export class WebSocketAgent {
const wsUrl = await this.executionContext.getAgentServerUrl();

return new Promise((resolve, reject) => {
this._publishMessage('🔗 Connecting to reasoning server...', 'thinking');
this._publishMessage('Getting ready...', 'thinking');
Logging.log("WebSocketAgent", `Connecting to ${wsUrl}`, "info");

// Create WebSocket
Expand All @@ -198,7 +192,6 @@ export class WebSocketAgent {
// WebSocket opened
this.ws.onopen = () => {
Logging.log("WebSocketAgent", "WebSocket connection opened", "info");
this._publishMessage('✅ WebSocket opened, waiting for server...', 'thinking');
};

// WebSocket message received
Expand All @@ -213,8 +206,6 @@ export class WebSocketAgent {
this.sessionId = data.data?.sessionId;
this.isConnected = true;

this._publishMessage('✅ Connected to reasoning server', 'thinking');

if (this.sessionId) {
Logging.log(
"WebSocketAgent",
Expand Down Expand Up @@ -356,25 +347,60 @@ ${formattedSteps}`;
// Update last event time for timeout tracking
this.lastEventTime = Date.now();

// Trigger glow
this._maybeStartGlow();

// Route based on message type
if (data.type === 'connection') {
// Already handled in _connect
return;
}
const isDev = isDevelopmentMode();

if (data.type === 'completion') {
this._handleCompletion(data);
return;
}
switch (data.type) {
case 'connection':
// Already handled in _connect
break;

if (data.type === 'error') {
this._handleError(data);
return;
}
case 'completion':
this._handleCompletion(data);
break;

case 'error':
this._handleError(data);
break;

case 'init':
if (isDev && data.content) {
this._publishMessage(data.content, 'thinking');
}
break;

// For all other types (response, tool_use, thinking, etc), publish content
if (data.content) {
this._publishMessage(data.content, 'thinking');
case 'thinking':
if (data.content) {
this._publishMessage(data.content, 'thinking');
}
break;

case 'tool_use':
if (data.content) {
this._publishMessage(data.content, 'thinking');
}
break;

case 'tool_result':
if (isDev && data.content) {
this._publishMessage(data.content, 'thinking');
}
break;

case 'response':
if (data.content) {
this._publishMessage(data.content, 'thinking');
}
break;

default:
if (isDev && data.content) {
Logging.log("WebSocketAgent", `Unknown message type: ${data.type}`, "warning");
this._publishMessage(data.content, 'thinking');
}
}

} catch (error) {
Expand Down Expand Up @@ -466,6 +492,21 @@ ${formattedSteps}`;
);
}

/**
* Start glow animation (fire and forget)
*/
private _maybeStartGlow(): void {
this.executionContext.browserContext.getCurrentPage()
.then(page => {
if (page?.tabId && !this.glowService.isGlowActive(page.tabId)) {
return this.glowService.startGlow(page.tabId);
}
})
.catch(error => {
Logging.log("WebSocketAgent", `Could not start glow: ${error}`, "warning");
});
}

/**
* Handle execution errors
*/
Expand Down