@@ -68,7 +68,7 @@ def framework_script
6868
6969 const llm = {
7070 truncate: _llm_truncate,
71- generate: _llm_generate,
71+ generate: function(prompt, options) { return _llm_generate(prompt, options); } ,
7272 };
7373
7474 const index = {
@@ -85,6 +85,7 @@ def framework_script
8585
8686 const chain = {
8787 setCustomRaw: _chain_set_custom_raw,
88+ streamCustomRaw: _chain_stream_custom_raw,
8889 };
8990
9091 const discourse = {
@@ -132,6 +133,27 @@ def framework_script
132133 }
133134 return result;
134135 },
136+ createStagedUser: function(params) {
137+ const result = _discourse_create_staged_user(params);
138+ if (result.error) {
139+ throw new Error(result.error);
140+ }
141+ return result;
142+ },
143+ createTopic: function(params) {
144+ const result = _discourse_create_topic(params);
145+ if (result.error) {
146+ throw new Error(result.error);
147+ }
148+ return result;
149+ },
150+ createPost: function(params) {
151+ const result = _discourse_create_post(params);
152+ if (result.error) {
153+ throw new Error(result.error);
154+ }
155+ return result;
156+ },
135157 };
136158
137159 const context = #{ JSON . generate ( @context . to_json ) } ;
@@ -182,11 +204,14 @@ def eval_with_timeout(script, timeout: nil)
182204 t &.join
183205 end
184206
185- def invoke
207+ def invoke ( progress_callback : nil )
208+ @progress_callback = progress_callback
186209 mini_racer_context . eval ( tool . script )
187210 eval_with_timeout ( "invoke(#{ JSON . generate ( parameters ) } )" )
188211 rescue MiniRacer ::ScriptTerminatedError
189212 { error : "Script terminated due to timeout" }
213+ ensure
214+ @progress_callback = nil
190215 end
191216
192217 def has_custom_context?
@@ -258,12 +283,22 @@ def attach_truncate(mini_racer_context)
258283
259284 mini_racer_context . attach (
260285 "_llm_generate" ,
261- -> ( prompt ) do
286+ -> ( prompt , options ) do
262287 in_attached_function do
288+ options ||= { }
289+ response_format = options [ "response_format" ]
290+ if response_format && !response_format . is_a? ( Hash )
291+ raise Discourse ::InvalidParameters . new ( "response_format must be a hash" )
292+ end
263293 @llm . generate (
264294 convert_js_prompt_to_ruby ( prompt ) ,
265295 user : llm_user ,
266296 feature_name : "custom_tool_#{ tool . name } " ,
297+ response_format : response_format ,
298+ temperature : options [ "temperature" ] ,
299+ top_p : options [ "top_p" ] ,
300+ max_tokens : options [ "max_tokens" ] ,
301+ stop_sequences : options [ "stop_sequences" ] ,
267302 )
268303 end
269304 end ,
@@ -316,6 +351,13 @@ def attach_index(mini_racer_context)
316351
317352 def attach_chain ( mini_racer_context )
318353 mini_racer_context . attach ( "_chain_set_custom_raw" , -> ( raw ) { self . custom_raw = raw } )
354+ mini_racer_context . attach (
355+ "_chain_stream_custom_raw" ,
356+ -> ( raw ) do
357+ self . custom_raw = raw
358+ @progress_callback . call ( raw ) if @progress_callback
359+ end ,
360+ )
319361 end
320362
321363 # this is useful for polling apis
@@ -499,6 +541,166 @@ def attach_discourse(mini_racer_context)
499541 end ,
500542 )
501543
544+ mini_racer_context . attach (
545+ "_discourse_create_staged_user" ,
546+ -> ( params ) do
547+ in_attached_function do
548+ params = params . symbolize_keys
549+ email = params [ :email ]
550+ username = params [ :username ]
551+ name = params [ :name ]
552+
553+ # Validate parameters
554+ return { error : "Missing required parameter: email" } if email . blank?
555+ return { error : "Missing required parameter: username" } if username . blank?
556+
557+ # Check if user already exists
558+ existing_user = User . find_by_email ( email ) || User . find_by_username ( username )
559+ return { error : "User already exists" , user_id : existing_user . id } if existing_user
560+
561+ begin
562+ user =
563+ User . create! (
564+ email : email ,
565+ username : username ,
566+ name : name || username ,
567+ staged : true ,
568+ approved : true ,
569+ trust_level : TrustLevel [ 0 ] ,
570+ )
571+
572+ { success : true , user_id : user . id , username : user . username , email : user . email }
573+ rescue => e
574+ { error : "Failed to create staged user: #{ e . message } " }
575+ end
576+ end
577+ end ,
578+ )
579+
580+ mini_racer_context . attach (
581+ "_discourse_create_topic" ,
582+ -> ( params ) do
583+ in_attached_function do
584+ params = params . symbolize_keys
585+ category_name = params [ :category_name ]
586+ category_id = params [ :category_id ]
587+ title = params [ :title ]
588+ raw = params [ :raw ]
589+ username = params [ :username ]
590+ tags = params [ :tags ]
591+
592+ if category_id . blank? && category_name . blank?
593+ return { error : "Missing required parameter: category_id or category_name" }
594+ end
595+ return { error : "Missing required parameter: title" } if title . blank?
596+ return { error : "Missing required parameter: raw" } if raw . blank?
597+
598+ user =
599+ if username . present?
600+ User . find_by ( username : username )
601+ else
602+ Discourse . system_user
603+ end
604+ return { error : "User not found: #{ username } " } if user . nil?
605+
606+ category =
607+ if category_id . present?
608+ Category . find_by ( id : category_id )
609+ else
610+ Category . find_by ( name : category_name ) || Category . find_by ( slug : category_name )
611+ end
612+
613+ return { error : "Category not found" } if category . nil?
614+
615+ begin
616+ post_creator =
617+ PostCreator . new (
618+ user ,
619+ title : title ,
620+ raw : raw ,
621+ category : category . id ,
622+ tags : tags ,
623+ skip_validations : true ,
624+ guardian : Guardian . new ( Discourse . system_user ) ,
625+ )
626+
627+ post = post_creator . create
628+
629+ if post_creator . errors . present?
630+ return { error : post_creator . errors . full_messages . join ( ", " ) }
631+ end
632+
633+ {
634+ success : true ,
635+ topic_id : post . topic_id ,
636+ post_id : post . id ,
637+ topic_slug : post . topic . slug ,
638+ topic_url : post . topic . url ,
639+ }
640+ rescue => e
641+ { error : "Failed to create topic: #{ e . message } " }
642+ end
643+ end
644+ end ,
645+ )
646+
647+ mini_racer_context . attach (
648+ "_discourse_create_post" ,
649+ -> ( params ) do
650+ in_attached_function do
651+ params = params . symbolize_keys
652+ topic_id = params [ :topic_id ]
653+ raw = params [ :raw ]
654+ username = params [ :username ]
655+ reply_to_post_number = params [ :reply_to_post_number ]
656+
657+ # Validate parameters
658+ return { error : "Missing required parameter: topic_id" } if topic_id . blank?
659+ return { error : "Missing required parameter: raw" } if raw . blank?
660+
661+ # Find the user
662+ user =
663+ if username . present?
664+ User . find_by ( username : username )
665+ else
666+ Discourse . system_user
667+ end
668+ return { error : "User not found: #{ username } " } if user . nil?
669+
670+ # Verify topic exists
671+ topic = Topic . find_by ( id : topic_id )
672+ return { error : "Topic not found" } if topic . nil?
673+
674+ begin
675+ post_creator =
676+ PostCreator . new (
677+ user ,
678+ raw : raw ,
679+ topic_id : topic_id ,
680+ reply_to_post_number : reply_to_post_number ,
681+ skip_validations : true ,
682+ guardian : Guardian . new ( Discourse . system_user ) ,
683+ )
684+
685+ post = post_creator . create
686+
687+ if post_creator . errors . present?
688+ return { error : post_creator . errors . full_messages . join ( ", " ) }
689+ end
690+
691+ {
692+ success : true ,
693+ post_id : post . id ,
694+ post_number : post . post_number ,
695+ cooked : post . cooked ,
696+ }
697+ rescue => e
698+ { error : "Failed to create post: #{ e . message } " }
699+ end
700+ end
701+ end ,
702+ )
703+
502704 mini_racer_context . attach (
503705 "_discourse_search" ,
504706 -> ( params ) do
0 commit comments