6
6
StoredCustomKeyEvent ,
7
7
StoredEvent ,
8
8
StoredRrwebEvent ,
9
+ StoredExtractionEvent ,
9
10
} from "../lib/types" ;
10
11
import {
11
12
ClickStep ,
@@ -15,6 +16,7 @@ import {
15
16
ScrollStep ,
16
17
Step ,
17
18
Workflow ,
19
+ ExtractStep ,
18
20
} from "../lib/workflow-types" ;
19
21
import {
20
22
HttpEvent ,
@@ -80,6 +82,8 @@ export default defineBackground(() => {
80
82
return null ; // Scroll steps will have null description like in the example
81
83
case "key_press" :
82
84
return "Key press element" ;
85
+ case "extract" :
86
+ return "Extract information with AI" ;
83
87
default :
84
88
return "Unknown action" ;
85
89
}
@@ -95,6 +99,10 @@ export default defineBackground(() => {
95
99
} )
96
100
. sort ( ( a , b ) => a . timestamp - b . timestamp ) ; // Sort chronologically
97
101
102
+ console . log ( `🔄 Processing ${ allSteps . length } steps for workflow update` ) ;
103
+ const extractionSteps = allSteps . filter ( s => ( s as any ) . type === 'extract' ) ;
104
+ console . log ( `🤖 Found ${ extractionSteps . length } extraction steps:` , extractionSteps ) ;
105
+
98
106
// Convert steps to semantic format with proper descriptions
99
107
const semanticSteps = allSteps . map ( ( step , index ) => {
100
108
const semanticStep : any = {
@@ -111,10 +119,15 @@ export default defineBackground(() => {
111
119
delete semanticStep . elementText ;
112
120
delete semanticStep . screenshot ;
113
121
114
- // Handle scroll steps specifically
122
+ // Handle different step types specifically
115
123
if ( step . type === "scroll" ) {
116
124
delete semanticStep . targetId ;
117
125
// Keep scrollX and scrollY for scroll steps
126
+ } else if ( step . type === "extract" ) {
127
+ // For extraction steps, preserve extractionGoal and url
128
+ // Keep: extractionGoal, url, type, description
129
+ // Already removed: timestamp, tabId, screenshot (these are correct to remove)
130
+ console . log ( `🤖 Processing extraction step:` , semanticStep ) ;
118
131
}
119
132
120
133
// Convert targetText to target_text for semantic workflow compatibility
@@ -129,6 +142,9 @@ export default defineBackground(() => {
129
142
return semanticStep ;
130
143
} ) ;
131
144
145
+ const semanticExtractionSteps = semanticSteps . filter ( s => s . type === 'extract' ) ;
146
+ console . log ( `✅ Final semantic steps include ${ semanticExtractionSteps . length } extraction steps:` , semanticExtractionSteps ) ;
147
+
132
148
// Create the workflowData object for the Python server (semantic format)
133
149
const semanticWorkflowData : Workflow = {
134
150
workflow_analysis : "Semantic version of recorded workflow. Uses visible text to identify elements instead of CSS selectors for improved reliability." ,
@@ -477,6 +493,24 @@ export default defineBackground(() => {
477
493
break ;
478
494
}
479
495
496
+ case "EXTRACTION_STEP" : {
497
+ const extractEvent = event as any ; // Type assertion for extraction event
498
+ if ( extractEvent . url && extractEvent . extractionGoal ) {
499
+ const step : ExtractStep = {
500
+ type : "extract" ,
501
+ timestamp : extractEvent . timestamp ,
502
+ tabId : extractEvent . tabId ,
503
+ url : extractEvent . url ,
504
+ extractionGoal : extractEvent . extractionGoal ,
505
+ screenshot : extractEvent . screenshot ,
506
+ } ;
507
+ steps . push ( step ) ;
508
+ } else {
509
+ console . warn ( "Skipping incomplete EXTRACTION_STEP:" , extractEvent ) ;
510
+ }
511
+ break ;
512
+ }
513
+
480
514
// Add cases for other StoredEvent types to Step types if needed
481
515
// e.g., CUSTOM_SELECT_EVENT -> SelectStep
482
516
// e.g., CUSTOM_TAB_CREATED -> TabCreatedStep
@@ -666,6 +700,83 @@ export default defineBackground(() => {
666
700
}
667
701
sendResponse ( { status : "stopped" } ) ; // Send simple confirmation
668
702
}
703
+ // --- Add Extraction Step from Sidepanel ---
704
+ else if ( message . type === "ADD_EXTRACTION_STEP" ) {
705
+ console . log ( "🤖 Received ADD_EXTRACTION_STEP request:" , message . payload ) ;
706
+
707
+ if ( ! isRecordingEnabled ) {
708
+ console . error ( "❌ Recording is not enabled" ) ;
709
+ sendResponse ( { status : "error" , message : "Recording is not active" } ) ;
710
+ return false ;
711
+ }
712
+
713
+ try {
714
+ // For sidepanel messages, we need to get the active tab
715
+ // Since this is from sidepanel, sender.tab will be undefined
716
+ // Let's use a direct approach with chrome.tabs.query but handle it synchronously
717
+
718
+ isAsync = true ;
719
+
720
+ chrome . tabs . query ( { active : true , currentWindow : true } , ( tabs ) => {
721
+ try {
722
+ console . log ( "📋 Active tabs found:" , tabs ?. length || 0 ) ;
723
+
724
+ if ( chrome . runtime . lastError ) {
725
+ console . error ( "❌ Chrome tabs query error:" , chrome . runtime . lastError ) ;
726
+ sendResponse ( { status : "error" , message : "Chrome tabs query failed" } ) ;
727
+ return ;
728
+ }
729
+
730
+ if ( ! tabs || tabs . length === 0 || ! tabs [ 0 ] ?. id ) {
731
+ console . error ( "❌ No active tab found" ) ;
732
+ sendResponse ( { status : "error" , message : "No active tab found" } ) ;
733
+ return ;
734
+ }
735
+
736
+ const tabId = tabs [ 0 ] . id ;
737
+ const tabUrl = tabs [ 0 ] . url || "" ;
738
+
739
+ console . log ( "✅ Using tab ID:" , tabId , "URL:" , tabUrl ) ;
740
+
741
+ const extractionStep : StoredExtractionEvent = {
742
+ timestamp : message . payload . timestamp ,
743
+ tabId : tabId ,
744
+ url : tabUrl ,
745
+ extractionGoal : message . payload . extractionGoal ,
746
+ messageType : "EXTRACTION_STEP" ,
747
+ } ;
748
+
749
+ console . log ( "📝 Creating extraction step:" , extractionStep ) ;
750
+
751
+ if ( ! sessionLogs [ tabId ] ) {
752
+ console . log ( "🆕 Initializing sessionLogs for tab:" , tabId ) ;
753
+ sessionLogs [ tabId ] = [ ] ;
754
+ }
755
+
756
+ sessionLogs [ tabId ] . push ( extractionStep ) ;
757
+ console . log ( "✅ Added extraction step to sessionLogs. Total events for tab:" , sessionLogs [ tabId ] . length ) ;
758
+
759
+ // Broadcast update (don't await to avoid blocking)
760
+ broadcastWorkflowDataUpdate ( ) ;
761
+ console . log ( "✅ Broadcasted workflow update" ) ;
762
+
763
+ // Send success response
764
+ sendResponse ( { status : "added" } ) ;
765
+
766
+ } catch ( error ) {
767
+ console . error ( "❌ Error in tabs.query callback:" , error ) ;
768
+ sendResponse ( { status : "error" , message : `Callback error: ${ error } ` } ) ;
769
+ }
770
+ } ) ;
771
+
772
+ return true ; // Keep message channel open
773
+
774
+ } catch ( error ) {
775
+ console . error ( "❌ Error setting up extraction step:" , error ) ;
776
+ sendResponse ( { status : "error" , message : `Setup error: ${ error } ` } ) ;
777
+ return false ;
778
+ }
779
+ }
669
780
// --- Status Request from Content Script ---
670
781
else if ( message . type === "REQUEST_RECORDING_STATUS" && sender . tab ?. id ) {
671
782
console . log (
0 commit comments