@@ -2,6 +2,9 @@ const DEFAULT_CLOUD_BRIDGE_URL = 'ws://127.0.0.1:17373/extension';
22const CLOUD_RUN_STORAGE_KEY = 'webbrainCloudRunSnapshots' ;
33const CLOUD_UPDATE_LIMIT = 200 ;
44const CLOUD_RUN_LIMIT = 50 ;
5+ const CLOUD_STRING_LIMIT = 16 * 1024 ;
6+ const CLOUD_RUN_PERSIST_BYTES_LIMIT = 256 * 1024 ;
7+ const CLOUD_PERSIST_BYTES_LIMIT = 4 * 1024 * 1024 ;
58const TERMINAL_STATUSES = new Set ( [ 'completed' , 'failed' , 'aborted' ] ) ;
69
710export function normalizeCloudBridgeUrl ( value = DEFAULT_CLOUD_BRIDGE_URL ) {
@@ -22,22 +25,85 @@ function scrubCloudValue(value) {
2225 if ( ( key === '_attachImage' || key === 'screenshot' ) && typeof item === 'string' && item . length > 500 ) {
2326 return `[large payload omitted: ${ item . length } chars]` ;
2427 }
28+ if ( typeof item === 'string' && item . length > CLOUD_STRING_LIMIT ) {
29+ return `${ item . slice ( 0 , CLOUD_STRING_LIMIT ) } \n[truncated ${ item . length - CLOUD_STRING_LIMIT } chars for cloud persistence]` ;
30+ }
2531 return item ;
2632 } ) ) ;
2733 } catch {
2834 return { unserializable : true } ;
2935 }
3036}
3137
38+ function serializedBytes ( value ) {
39+ return new TextEncoder ( ) . encode ( JSON . stringify ( value ) ) . length ;
40+ }
41+
42+ function compactCloudRunForPersistence ( run ) {
43+ const row = scrubCloudValue ( run ) ;
44+ row . structured = row . structured ?? ! ! run ?. outputSchema ;
45+ if ( serializedBytes ( row ) <= CLOUD_RUN_PERSIST_BYTES_LIMIT ) return row ;
46+
47+ const omittedUpdates = Array . isArray ( row . updates ) ? row . updates . length : 0 ;
48+ row . updates = [ ] ;
49+ row . persistenceTruncated = { omittedUpdates } ;
50+ if ( serializedBytes ( row ) <= CLOUD_RUN_PERSIST_BYTES_LIMIT ) return row ;
51+
52+ row . content = '' ;
53+ row . outputSchema = null ;
54+ row . persistenceTruncated . omittedContent = true ;
55+ row . persistenceTruncated . omittedSchema = true ;
56+ if ( serializedBytes ( row ) <= CLOUD_RUN_PERSIST_BYTES_LIMIT ) return row ;
57+
58+ delete row . result ;
59+ row . persistenceTruncated . omittedResult = true ;
60+ if ( serializedBytes ( row ) <= CLOUD_RUN_PERSIST_BYTES_LIMIT ) return row ;
61+
62+ return scrubCloudValue ( {
63+ runId : run ?. runId ,
64+ status : run ?. status ,
65+ tabId : run ?. tabId ,
66+ task : run ?. task ,
67+ structured : ! ! run ?. outputSchema || run ?. structured === true ,
68+ summary : run ?. summary ,
69+ content : '' ,
70+ finalUrl : run ?. finalUrl ,
71+ error : run ?. error ,
72+ createdAt : run ?. createdAt ,
73+ updatedAt : run ?. updatedAt ,
74+ completedAt : run ?. completedAt ,
75+ updates : [ ] ,
76+ persistenceTruncated : { omittedUpdates, omittedResult : true , omittedSchema : true } ,
77+ } ) ;
78+ }
79+
80+ export function buildCloudPersistenceRows ( runs ) {
81+ const values = Array . isArray ( runs ) ? [ ...runs ] : [ ...( runs ?. values ?. ( ) || [ ] ) ] ;
82+ const candidates = values
83+ . sort ( ( a , b ) => String ( b ?. createdAt || '' ) . localeCompare ( String ( a ?. createdAt || '' ) ) )
84+ . slice ( 0 , CLOUD_RUN_LIMIT )
85+ . map ( compactCloudRunForPersistence ) ;
86+ const rows = [ ] ;
87+ let totalBytes = 2 ;
88+ for ( const row of candidates ) {
89+ const rowBytes = serializedBytes ( row ) + ( rows . length ? 1 : 0 ) ;
90+ if ( totalBytes + rowBytes > CLOUD_PERSIST_BYTES_LIMIT ) continue ;
91+ rows . push ( row ) ;
92+ totalBytes += rowBytes ;
93+ }
94+ return rows ;
95+ }
96+
3297function cloudSnapshot ( run , { includeUpdates = true } = { } ) {
3398 if ( ! run ) return null ;
3499 return {
35100 runId : run . runId ,
36101 status : run . status ,
37102 tabId : run . tabId ,
38103 task : run . task ,
39- structured : ! ! run . outputSchema ,
104+ structured : run . structured ?? ! ! run . outputSchema ,
40105 result : run . result ,
106+ persistenceTruncated : run . persistenceTruncated ,
41107 summary : run . summary ,
42108 content : run . content ,
43109 finalUrl : run . finalUrl ,
@@ -79,10 +145,7 @@ export function createCloudRunController({
79145
80146 async function persist ( ) {
81147 if ( ! api . storage ?. session ?. set ) return ;
82- const rows = [ ...runs . values ( ) ]
83- . sort ( ( a , b ) => String ( b . createdAt ) . localeCompare ( String ( a . createdAt ) ) )
84- . slice ( 0 , CLOUD_RUN_LIMIT )
85- . map ( run => scrubCloudValue ( run ) ) ;
148+ const rows = buildCloudPersistenceRows ( runs ) ;
86149 persistQueue = persistQueue
87150 . catch ( ( ) => { } )
88151 . then ( ( ) => api . storage . session . set ( { [ CLOUD_RUN_STORAGE_KEY ] : rows } ) ) ;
0 commit comments