| 42 | } |
| 43 | |
| 44 | func (c *codeModeTool) runJavascript(ctx context.Context, script string) (ScriptResult, error) { |
| 45 | vm := goja.New() |
| 46 | tracker := &toolCallTracker{} |
| 47 | |
| 48 | // Always stamp a hash + length so dashboards can correlate |
| 49 | // identical scripts ("model ran the same script 200 times this |
| 50 | // hour") without ever shipping the body. Codemode scripts are |
| 51 | // kilobyte-scale arbitrary JS — embedded auth tokens, pasted |
| 52 | // user data, and inline secrets are common — so the body itself |
| 53 | // is gated behind the GenAI content-capture opt-in. |
| 54 | span := trace.SpanFromContext(ctx) |
| 55 | if span.IsRecording() { |
| 56 | sum := sha256.Sum256([]byte(script)) |
| 57 | span.SetAttributes( |
| 58 | attribute.String("cagent.tool.codemode.script_hash", hex.EncodeToString(sum[:])), |
| 59 | attribute.Int("cagent.tool.codemode.script_length", len(script)), |
| 60 | ) |
| 61 | if genai.IsContentCaptureEnabled() { |
| 62 | span.SetAttributes(attribute.String("cagent.tool.codemode.script", script)) |
| 63 | } |
| 64 | } |
| 65 | defer func() { |
| 66 | if span.IsRecording() { |
| 67 | span.SetAttributes(attribute.Int("cagent.tool.codemode.tool_call_count", len(tracker.calls))) |
| 68 | } |
| 69 | }() |
| 70 | |
| 71 | // Inject console object to the help the LLM debug its own code. |
| 72 | var ( |
| 73 | stdOut bytes.Buffer |
| 74 | stdErr bytes.Buffer |
| 75 | ) |
| 76 | _ = vm.Set("console", console(&stdOut, &stdErr)) |
| 77 | |
| 78 | // Inject every tool as a javascript function. |
| 79 | for _, toolset := range c.toolsets { |
| 80 | allTools, err := toolset.Tools(ctx) |
| 81 | if err != nil { |
| 82 | return ScriptResult{}, err |
| 83 | } |
| 84 | |
| 85 | for _, tool := range allTools { |
| 86 | _ = vm.Set(tool.Name, callTool(ctx, tool, tracker)) |
| 87 | } |
| 88 | } |
| 89 | |
| 90 | // Wrap the user script in an IIFE to allow top-level returns. |
| 91 | script = "(() => {\n" + script + "\n})()" |
| 92 | |
| 93 | // Run the script. |
| 94 | v, err := vm.RunString(script) |
| 95 | if err != nil { |
| 96 | // Script execution failed - include tool call history to help LLM understand what went wrong |
| 97 | return ScriptResult{ |
| 98 | StdOut: stdOut.String(), |
| 99 | StdErr: stdErr.String(), |
| 100 | Value: err.Error(), |
| 101 | ToolCalls: tracker.calls, |