@@ -183,13 +183,16 @@ func generateToolsForBlock(block *waveobj.Block) []uctypes.ToolDefinition {
183183 // Check if tsunami widget is running
184184 status := blockcontroller .GetBlockControllerRuntimeStatus (block .OID )
185185 if status != nil && status .ShellProcStatus == blockcontroller .Status_Running && status .TsunamiPort > 0 {
186- // Check if schemas are available
187186 blockORef := waveobj .MakeORef (waveobj .OType_Block , block .OID )
188187 rtInfo := wstore .GetRTInfo (blockORef )
189- if rtInfo != nil && rtInfo .TsunamiSchemas != nil {
190- if tool := GetTsunamiGetDataToolDefinition (block , rtInfo , status ); tool != nil {
191- tools = append (tools , * tool )
192- }
188+ if tool := GetTsunamiGetDataToolDefinition (block , rtInfo , status ); tool != nil {
189+ tools = append (tools , * tool )
190+ }
191+ if tool := GetTsunamiGetConfigToolDefinition (block , rtInfo , status ); tool != nil {
192+ tools = append (tools , * tool )
193+ }
194+ if tool := GetTsunamiSetConfigToolDefinition (block , rtInfo , status ); tool != nil {
195+ tools = append (tools , * tool )
193196 }
194197 }
195198 }
@@ -245,59 +248,131 @@ func GetWebNavigateToolDefinition(block *waveobj.Block) uctypes.ToolDefinition {
245248 }
246249}
247250
251+ func makeTsunamiGetCallback (status * blockcontroller.BlockControllerRuntimeStatus , apiPath string ) func (any ) (any , error ) {
252+ return func (input any ) (any , error ) {
253+ if status .TsunamiPort == 0 {
254+ return nil , fmt .Errorf ("tsunami port not available" )
255+ }
256+
257+ url := fmt .Sprintf ("http://localhost:%d%s" , status .TsunamiPort , apiPath )
258+
259+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
260+ defer cancel ()
261+
262+ req , err := http .NewRequestWithContext (ctx , "GET" , url , nil )
263+ if err != nil {
264+ return nil , fmt .Errorf ("failed to create request: %w" , err )
265+ }
266+
267+ resp , err := http .DefaultClient .Do (req )
268+ if err != nil {
269+ return nil , fmt .Errorf ("failed to make request to tsunami: %w" , err )
270+ }
271+ defer resp .Body .Close ()
272+
273+ if resp .StatusCode != http .StatusOK {
274+ return nil , fmt .Errorf ("tsunami returned status %d" , resp .StatusCode )
275+ }
276+
277+ var result any
278+ if err := json .NewDecoder (resp .Body ).Decode (& result ); err != nil {
279+ return nil , fmt .Errorf ("failed to decode tsunami response: %w" , err )
280+ }
281+
282+ return result , nil
283+ }
284+ }
285+
286+ func makeTsunamiPostCallback (status * blockcontroller.BlockControllerRuntimeStatus , apiPath string ) func (any ) (any , error ) {
287+ return func (input any ) (any , error ) {
288+ if status .TsunamiPort == 0 {
289+ return nil , fmt .Errorf ("tsunami port not available" )
290+ }
291+
292+ url := fmt .Sprintf ("http://localhost:%d%s" , status .TsunamiPort , apiPath )
293+
294+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
295+ defer cancel ()
296+
297+ var reqBody []byte
298+ var err error
299+ if input != nil {
300+ reqBody , err = json .Marshal (input )
301+ if err != nil {
302+ return nil , fmt .Errorf ("failed to marshal input: %w" , err )
303+ }
304+ }
305+
306+ req , err := http .NewRequestWithContext (ctx , "POST" , url , strings .NewReader (string (reqBody )))
307+ if err != nil {
308+ return nil , fmt .Errorf ("failed to create request: %w" , err )
309+ }
310+ req .Header .Set ("Content-Type" , "application/json" )
311+
312+ resp , err := http .DefaultClient .Do (req )
313+ if err != nil {
314+ return nil , fmt .Errorf ("failed to make request to tsunami: %w" , err )
315+ }
316+ defer resp .Body .Close ()
317+
318+ if resp .StatusCode != http .StatusOK {
319+ return nil , fmt .Errorf ("tsunami returned status %d" , resp .StatusCode )
320+ }
321+
322+ return true , nil
323+ }
324+ }
325+
248326func GetTsunamiGetDataToolDefinition (block * waveobj.Block , rtInfo * waveobj.ObjRTInfo , status * blockcontroller.BlockControllerRuntimeStatus ) * uctypes.ToolDefinition {
249327 blockIdPrefix := block .OID [:8 ]
250328 toolName := fmt .Sprintf ("tsunami_getdata_%s" , blockIdPrefix )
251329
330+ return & uctypes.ToolDefinition {
331+ Name : toolName ,
332+ InputSchema : map [string ]any {
333+ "type" : "object" ,
334+ "properties" : map [string ]any {},
335+ },
336+ ToolAnyCallback : makeTsunamiGetCallback (status , "/api/data" ),
337+ }
338+ }
339+
340+ func GetTsunamiGetConfigToolDefinition (block * waveobj.Block , rtInfo * waveobj.ObjRTInfo , status * blockcontroller.BlockControllerRuntimeStatus ) * uctypes.ToolDefinition {
341+ blockIdPrefix := block .OID [:8 ]
342+ toolName := fmt .Sprintf ("tsunami_getconfig_%s" , blockIdPrefix )
343+
344+ return & uctypes.ToolDefinition {
345+ Name : toolName ,
346+ InputSchema : map [string ]any {
347+ "type" : "object" ,
348+ "properties" : map [string ]any {},
349+ },
350+ ToolAnyCallback : makeTsunamiGetCallback (status , "/api/config" ),
351+ }
352+ }
353+
354+ func GetTsunamiSetConfigToolDefinition (block * waveobj.Block , rtInfo * waveobj.ObjRTInfo , status * blockcontroller.BlockControllerRuntimeStatus ) * uctypes.ToolDefinition {
355+ blockIdPrefix := block .OID [:8 ]
356+ toolName := fmt .Sprintf ("tsunami_setconfig_%s" , blockIdPrefix )
357+
252358 var inputSchema map [string ]any
253359 if rtInfo != nil && rtInfo .TsunamiSchemas != nil {
254360 if schemasMap , ok := rtInfo .TsunamiSchemas .(map [string ]any ); ok {
255- if dataSchema , exists := schemasMap ["data " ]; exists {
256- inputSchema = dataSchema .(map [string ]any )
361+ if configSchema , exists := schemasMap ["config " ]; exists {
362+ inputSchema = configSchema .(map [string ]any )
257363 }
258364 }
259365 }
260366
261- // Return nil if no data schema found
367+ // Return nil if no config schema found
262368 if inputSchema == nil {
263369 return nil
264370 }
265371
266372 return & uctypes.ToolDefinition {
267- Name : toolName ,
268- InputSchema : inputSchema ,
269- ToolAnyCallback : func (input any ) (any , error ) {
270- if status .TsunamiPort == 0 {
271- return nil , fmt .Errorf ("tsunami port not available" )
272- }
273-
274- url := fmt .Sprintf ("http://localhost:%d/api/data" , status .TsunamiPort )
275-
276- ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
277- defer cancel ()
278-
279- req , err := http .NewRequestWithContext (ctx , "GET" , url , nil )
280- if err != nil {
281- return nil , fmt .Errorf ("failed to create request: %w" , err )
282- }
283-
284- resp , err := http .DefaultClient .Do (req )
285- if err != nil {
286- return nil , fmt .Errorf ("failed to make request to tsunami: %w" , err )
287- }
288- defer resp .Body .Close ()
289-
290- if resp .StatusCode != http .StatusOK {
291- return nil , fmt .Errorf ("tsunami returned status %d" , resp .StatusCode )
292- }
293-
294- var result any
295- if err := json .NewDecoder (resp .Body ).Decode (& result ); err != nil {
296- return nil , fmt .Errorf ("failed to decode tsunami response: %w" , err )
297- }
298-
299- return result , nil
300- },
373+ Name : toolName ,
374+ InputSchema : inputSchema ,
375+ ToolAnyCallback : makeTsunamiPostCallback (status , "/api/config" ),
301376 }
302377}
303378
0 commit comments