executeSandboxCodeWithResult executes code and returns full result including output files
(ctx context.Context, language string, code string)
| 167 | |
| 168 | // executeSandboxCodeWithResult executes code and returns full result including output files |
| 169 | func executeSandboxCodeWithResult(ctx context.Context, language string, code string) (*ToolResult, error) { |
| 170 | reqPayload := buildSandboxRequest(ctx, language, code) |
| 171 | if err := ensureSandboxSessionSeeded(ctx, reqPayload.SessionID, reqPayload.Cwd); err != nil { |
| 172 | return nil, err |
| 173 | } |
| 174 | if err := preflightSandboxClientCode(ctx, reqPayload.SessionID, reqPayload.Cwd, language, code); err != nil { |
| 175 | return nil, err |
| 176 | } |
| 177 | |
| 178 | jsonData, err := json.Marshal(reqPayload) |
| 179 | if err != nil { |
| 180 | return nil, fmt.Errorf("failed to marshal sandbox request: %v", err) |
| 181 | } |
| 182 | |
| 183 | url := fmt.Sprintf("%s/execute", strings.TrimRight(config.SandboxServiceURL, "/")) |
| 184 | logSandboxRequestDebug(ctx, "execute", url, reqPayload, jsonData) |
| 185 | var sandboxResp *sandboxclient.ExecuteCodeResponse |
| 186 | |
| 187 | // Execute with retry logic for transient failures |
| 188 | retryErr := common.Retry(ctx, func() error { |
| 189 | resp, httpErr := getSandboxClient().ExecuteCode(ctx, convertToSandboxClientExecuteRequest(reqPayload)) |
| 190 | if httpErr != nil { |
| 191 | logger.Warnf(ctx, "Sandbox service request failed: %v", httpErr) |
| 192 | return httpErr |
| 193 | } |
| 194 | sandboxResp = resp |
| 195 | return nil |
| 196 | }, |
| 197 | common.WithMaxRetries(3), |
| 198 | common.WithInitialDelay(500*time.Millisecond), |
| 199 | common.WithRetryableFunc(common.IsRetryableError), |
| 200 | ) |
| 201 | |
| 202 | if retryErr != nil { |
| 203 | logger.Errorf(ctx, "Sandbox service unavailable after retries: %v", retryErr) |
| 204 | return nil, fmt.Errorf("工具服务暂时不可用,请稍后重试") |
| 205 | } |
| 206 | logSandboxResponseDebug(ctx, "execute", convertFromSandboxClientExecuteResponse(sandboxResp)) |
| 207 | outputFiles, snapshot := filterSandboxOutputFilesBySnapshot(loadSandboxOutputSnapshot(ctx), convertSandboxOutputFiles(sandboxResp.OutputFiles)) |
| 208 | rememberSandboxOutputSnapshot(ctx, snapshot) |
| 209 | |
| 210 | return &ToolResult{ |
| 211 | Output: formatCommandResult(sandboxResp.Stdout, sandboxResp.Stderr, sandboxResp.ExitCode), |
| 212 | Stderr: sandboxResp.Stderr, |
| 213 | ExitCode: sandboxResp.ExitCode, |
| 214 | OutputFiles: outputFiles, |
| 215 | }, nil |
| 216 | } |
| 217 | |
| 218 | // executeSandboxCode handles the HTTP communication with the Sandbox Service |
| 219 | // with retry logic for transient failures |
no test coverage detected