Skip to content

Commit 8938e62

Browse files
authored
Teach Mode - fixes (#127)
* editable goal * editable goal UI + saving updates to workflow * show details when view processing is done * fix: processing title * fix: progress counter in preprocessing agent * UI: hide pause/reset in teach mode * UI: background and other consistency fixes * remove un-used components
1 parent 0552ce7 commit 8938e62

21 files changed

+391
-201
lines changed

src/background/handlers/TeachModeHandler.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,4 +359,29 @@ export class TeachModeHandler {
359359
})
360360
}
361361
}
362+
363+
/**
364+
* Handle update workflow request
365+
*/
366+
async handleTeachModeUpdateWorkflow(
367+
message: PortMessage,
368+
port: chrome.runtime.Port
369+
): Promise<void> {
370+
try {
371+
const { recordingId, updates } = message.payload as any
372+
const success = await this.teachModeService.updateWorkflow(recordingId, updates)
373+
port.postMessage({
374+
type: MessageType.TEACH_MODE_UPDATE_WORKFLOW,
375+
payload: { success },
376+
id: message.id
377+
})
378+
} catch (error) {
379+
const errorMessage = error instanceof Error ? error.message : String(error)
380+
port.postMessage({
381+
type: MessageType.TEACH_MODE_UPDATE_WORKFLOW,
382+
payload: { success: false, error: errorMessage },
383+
id: message.id
384+
})
385+
}
386+
}
362387
}

src/background/index.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ function registerHandlers(): void {
197197
(msg, port) => teachModeHandler.handleTeachModeGetWorkflow(msg, port)
198198
)
199199

200+
messageRouter.registerHandler(
201+
MessageType.TEACH_MODE_UPDATE_WORKFLOW,
202+
(msg, port) => teachModeHandler.handleTeachModeUpdateWorkflow(msg, port)
203+
)
204+
200205
// Log handler
201206
messageRouter.registerHandler(
202207
MessageType.LOG_MESSAGE,

src/lib/agent/PreprocessAgent.ts

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -66,21 +66,25 @@ export class PreprocessAgent {
6666
const validatedRecording = TeachModeRecordingSchema.parse(recording);
6767
Logging.log("PreprocessAgent", `Processing recording with ${validatedRecording.events.length} events`, "info");
6868

69+
// Filter out session events for processing count
70+
const eventsToProcess = validatedRecording.events.filter(
71+
e => e.action.type !== 'session_start' && e.action.type !== 'session_end'
72+
);
73+
6974
// Emit preprocessing started
7075
this._emitProgress('preprocessing_started', {
71-
totalEvents: validatedRecording.events.filter(
72-
e => e.action.type !== 'session_start' && e.action.type !== 'session_end'
73-
).length
76+
totalEvents: eventsToProcess.length
7477
});
7578

7679
// Transcribe audio if present and narration not already set
7780
let transcript = validatedRecording.narration?.transcript || "";
7881
if (!transcript && validatedRecording.audio) {
7982
Logging.log("PreprocessAgent", "Transcribing audio recording...", "info");
8083

81-
// Emit progress for transcription stage
8284
this._emitProgress('preprocessing_progress', {
8385
stage: 'transcription',
86+
current: 0,
87+
total: eventsToProcess.length,
8488
message: 'Transcribing audio narration...'
8589
});
8690

@@ -91,17 +95,19 @@ export class PreprocessAgent {
9195
// Emit debug info for transcript
9296
this._emitDebug('Transcript extracted', transcript);
9397

94-
// Emit progress with transcription complete
9598
this._emitProgress('preprocessing_progress', {
9699
stage: 'transcription',
100+
current: 0,
101+
total: eventsToProcess.length,
97102
message: 'Transcription completed',
98103
transcript
99104
});
100105
} catch (error) {
101106
Logging.log("PreprocessAgent", `Transcription failed: ${error}`, "warning");
102-
// Continue without transcript - no special error event needed
103107
this._emitProgress('preprocessing_progress', {
104108
stage: 'transcription',
109+
current: 0,
110+
total: eventsToProcess.length,
105111
message: 'Continuing without transcription',
106112
error: String(error)
107113
});
@@ -118,11 +124,6 @@ export class PreprocessAgent {
118124
const steps: SemanticWorkflow['steps'] = [];
119125
let previousState: StateSnapshot | undefined;
120126

121-
// Filter out session events for processing count
122-
const eventsToProcess = validatedRecording.events.filter(
123-
e => e.action.type !== 'session_start' && e.action.type !== 'session_end'
124-
);
125-
126127
let processedCount = 0;
127128
for (let i = 0; i < validatedRecording.events.length; i++) {
128129
const event = validatedRecording.events[i];

src/lib/services/TeachModeService.ts

Lines changed: 15 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -412,10 +412,15 @@ export class TeachModeService {
412412
try {
413413
const storage = RecordingStorage.getInstance()
414414

415-
// Generate title based on URL and time
415+
// Generate title with processing indicator
416416
const url = new URL(recording.session.url)
417417
const date = new Date(recording.session.startTimestamp)
418-
const title = `${url.hostname} - ${date.toLocaleString()}`
418+
const timeString = date.toLocaleTimeString('en-US', {
419+
hour: '2-digit',
420+
minute: '2-digit',
421+
hour12: true
422+
})
423+
const title = `Processing - ${url.hostname} ${timeString}`
419424

420425
// Save recording to storage immediately
421426
const recordingId = await storage.save(recording, title)
@@ -424,12 +429,6 @@ export class TeachModeService {
424429
// Start async preprocessing - fire and forget
425430
this._startAsyncPreprocessing(recordingId, recording)
426431

427-
// Optionally export immediately
428-
if (await this._shouldAutoExport()) {
429-
await storage.export(recordingId)
430-
Logging.log('TeachModeService', `Auto-exported recording ${recordingId}`)
431-
}
432-
433432
return recordingId
434433
} catch (error) {
435434
Logging.log('TeachModeService', `Failed to save recording: ${error}`, 'error')
@@ -492,18 +491,6 @@ export class TeachModeService {
492491
}
493492
}
494493

495-
/**
496-
* Check if auto-export is enabled
497-
*/
498-
private async _shouldAutoExport(): Promise<boolean> {
499-
try {
500-
const result = await chrome.storage.local.get('teachMode_autoExport')
501-
return result.teachMode_autoExport === true
502-
} catch {
503-
return false
504-
}
505-
}
506-
507494
/**
508495
* Cleanup when tab is closed
509496
*/
@@ -562,6 +549,14 @@ export class TeachModeService {
562549
return await storage.getWorkflow(recordingId)
563550
}
564551

552+
/**
553+
* Update workflow for a recording with partial changes
554+
*/
555+
async updateWorkflow(recordingId: string, updates: any): Promise<boolean> {
556+
const storage = RecordingStorage.getInstance()
557+
return await storage.updateWorkflow(recordingId, updates)
558+
}
559+
565560
/**
566561
* Delete workflow for a recording
567562
*/

src/lib/teach-mode/storage/RecordingStorage.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,40 @@ export class RecordingStorage {
132132
}
133133
}
134134

135+
/**
136+
* Update an existing workflow with partial changes
137+
*/
138+
async updateWorkflow(recordingId: string, updates: Partial<SemanticWorkflow>): Promise<boolean> {
139+
try {
140+
// Get existing workflow
141+
const existingWorkflow = await this.getWorkflow(recordingId)
142+
if (!existingWorkflow) {
143+
Logging.log('RecordingStorage', `Workflow for recording ${recordingId} not found`, 'warning')
144+
return false
145+
}
146+
147+
// Deep merge updates with existing workflow
148+
const updatedWorkflow: SemanticWorkflow = {
149+
...existingWorkflow,
150+
metadata: {
151+
...existingWorkflow.metadata,
152+
...(updates.metadata || {})
153+
},
154+
steps: updates.steps || existingWorkflow.steps
155+
}
156+
157+
// Save the updated workflow
158+
await this.saveWorkflow(recordingId, updatedWorkflow)
159+
160+
Logging.log('RecordingStorage', `Updated workflow for recording ${recordingId}`)
161+
return true
162+
163+
} catch (error) {
164+
Logging.log('RecordingStorage', `Failed to update workflow for ${recordingId}: ${error}`, 'error')
165+
return false
166+
}
167+
}
168+
135169
/**
136170
* Get a recording by ID
137171
*/

src/lib/types/messaging.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ export enum MessageType {
5252
TEACH_MODE_STATS = 'TEACH_MODE_STATS',
5353
TEACH_MODE_SEARCH = 'TEACH_MODE_SEARCH',
5454
TEACH_MODE_GET_WORKFLOW = 'TEACH_MODE_GET_WORKFLOW',
55+
TEACH_MODE_UPDATE_WORKFLOW = 'TEACH_MODE_UPDATE_WORKFLOW',
5556
EXECUTE_TEACH_MODE_WORKFLOW = 'EXECUTE_TEACH_MODE_WORKFLOW',
5657
}
5758

src/sidepanel/App.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@ export function App() {
8686
}}
8787
showReset={messages.length > 0 || (appMode === 'teach' && teachModeState !== 'idle')}
8888
isProcessing={isExecuting}
89+
isTeachMode={appMode === 'teach'}
8990
/>
9091

9192
{/* Main content area - changes based on mode */}

src/sidepanel/components/Header.tsx

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ interface HeaderProps {
2222
onReset: () => void
2323
showReset: boolean // This now means "has messages to reset"
2424
isProcessing: boolean
25+
isTeachMode?: boolean // Hide pause/reset buttons in teach mode
2526
}
2627

2728
/**
2829
* Header component for the sidepanel
2930
* Displays title, connection status, and action buttons (pause/reset)
3031
* Memoized to prevent unnecessary re-renders
3132
*/
32-
export const Header = memo(function Header({ onReset, showReset, isProcessing }: HeaderProps) {
33+
export const Header = memo(function Header({ onReset, showReset, isProcessing, isTeachMode = false }: HeaderProps) {
3334
const { sendMessage, connected, addMessageListener, removeMessageListener } = useSidePanelPortMessaging()
3435
const { trackClick } = useAnalytics()
3536
const [showSettings, setShowSettings] = useState(false)
@@ -308,8 +309,8 @@ export const Header = memo(function Header({ onReset, showReset, isProcessing }:
308309
</div>
309310
)}
310311

311-
{/* Show Pause button if processing */}
312-
{isProcessing && (
312+
{/* Show Pause button if processing and NOT in teach mode */}
313+
{isProcessing && !isTeachMode && (
313314
<Button
314315
onClick={handleCancel}
315316
variant="ghost"
@@ -321,9 +322,9 @@ export const Header = memo(function Header({ onReset, showReset, isProcessing }:
321322
<Pause className="w-4 h-4" />
322323
</Button>
323324
)}
324-
325-
{/* Show Reset button if has messages */}
326-
{showReset && (
325+
326+
{/* Show Reset button if has messages and NOT in teach mode */}
327+
{showReset && !isTeachMode && (
327328
<Button
328329
onClick={handleReset}
329330
variant="ghost"

0 commit comments

Comments
 (0)